From 9aca0d5f6e2f27a0dd1cb8560bd5aec3317d6205 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 12 Oct 2004 01:34:32 +0000 Subject: [PATCH] - Check whether libXft is at least version 2.1.2 else refuse to compile. - Fixed bug in icon chooser dialog that could cause a segmentation fault in some cases (Pascal Hofstee ) - Fixed crash in asm code in wrlib, with new versions of gcc. - Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly used the r, g, b fields in the conversion. - Fixed x86 ASM code in wrlib to work on 64 bit architectures. - Fixed the focus flicker seen with some apps (notably gtk2) (Alexey Spiridonov ) - Fixed all crashing bugs that were generated by wmaker starting with the WMState file missing. - Added NetWM support (a modified version of the patch originaly written by Peter Zijlstra ) - Applied patch to enhance the Virtual Desktop behaviour, and to integrate it with the NetWM code (Peter Zijlstra ) - Applied a few xinerama and placement fixes (Peter Zijlstra ) - Fixed memory leak in dock code. - Fixed and enhanced the text wrapping in WINGs. - Fixed the layout of some elements in WPrefs.app - Added workaround for aplications that don't set the required hints on the client leader window, but they set them on normal windows (observer with KDE 3.3.0 mainly). This will allow these apps to get an appicon again. (they should be fixed still) - Added workaround for applications that do not set a command with XSetCommand(), but instead they set the _NET_WM_PID property. This works with operating systems that offer a /proc interface similar to what linux has. (This also is to fix problems with KDE 3.3.0 apps, but not only them). - Fixed bug with autostart and exit scripts not being executed if user GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT) - Added utf8 support in WINGs (removed old X core font code) - Added utility to convert old font names to new font names in style files --- ChangeLog | 33 +- TODO | 1 - WINGs/ChangeLog | 7 +- WINGs/Examples/puzzle.c | 11 +- WINGs/Extras/Makefile.am | 1 + WINGs/Makefile.am | 4 +- WINGs/Tests/wtest.c | 10 +- WINGs/WINGs/WINGs.h | 7 +- WINGs/WINGs/WINGsP.h | 11 +- WINGs/configuration.c | 5 +- WINGs/dragcommon.c | 13 +- WINGs/dragdestination.c | 5 +- WINGs/dragsource.c | 6 +- WINGs/python/WINGs.py | 14 +- WINGs/userdefaults.c | 10 +- WINGs/wevent.c | 4 +- WINGs/wfont.c | 2050 ++++++---------------------- WINGs/wfont_noxft.c | 769 +++++++++++ WINGs/wfont_wchar.c | 599 ++++++++ WINGs/wfontpanel.c | 999 +++++++++----- WINGs/wframe.c | 13 +- WINGs/widgets.c | 17 +- WINGs/winputmethod.c | 19 +- WINGs/wmisc.c | 116 +- WINGs/wscroller.c | 7 +- WINGs/wtext.c | 2 +- WPrefs.app/Appearance.c | 4 +- WPrefs.app/Expert.c | 2 +- WPrefs.app/Focus.c | 24 +- WPrefs.app/Font.c | 66 +- WPrefs.app/KeyboardShortcuts.c | 16 +- WPrefs.app/Makefile.am | 4 +- WPrefs.app/WPrefs.c | 4 +- WPrefs.app/WindowHandling.c | 12 +- WPrefs.app/Workspace.c | 6 +- WindowMaker/Defaults/WMWindowAttributes.in | 3 + acinclude.m4 | 36 + configure.ac | 130 +- src/Makefile.am | 6 +- src/WindowMaker.h | 62 +- src/actions.c | 351 +++-- src/actions.h | 4 + src/appicon.c | 2 +- src/application.c | 29 +- src/application.h | 2 +- src/client.c | 49 +- src/cycling.c | 28 +- src/defaults.c | 39 +- src/dialog.c | 34 +- src/dock.c | 137 +- src/event.c | 124 +- src/framewin.c | 15 +- src/funcs.h | 12 + src/icon.c | 11 +- src/keybind.h | 18 +- src/main.c | 36 +- src/menu.c | 5 +- src/misc.c | 255 +++- src/moveres.c | 112 +- src/placement.c | 77 +- src/screen.c | 52 +- src/screen.h | 7 +- src/session.c | 31 +- src/stacking.c | 12 + src/startup.c | 15 +- src/text.c | 19 +- src/wdefaults.c | 2 +- src/window.c | 546 +++++--- src/window.h | 34 +- src/winmenu.c | 4 +- src/winspector.c | 14 +- src/wmspec.c | 1607 ++++++++++++++++++---- src/wmspec.h | 15 + src/workspace.c | 742 ++++++++-- src/workspace.h | 11 +- src/xdnd.c | 2 +- src/xutil.c | 1 + test/wtest.c | 1 + util/Makefile.am | 7 +- util/convertfonts.c | 317 +++++ util/geticonset.c | 7 +- util/getstyle.c | 8 +- util/wmagnify.c | 1 + util/wmsetbg.c | 2 +- wmlib/app.c | 1 + wrlib/convert.c | 3 +- wrlib/draw.c | 2 +- wrlib/x86_specific.c | 1454 ++++++++++---------- 88 files changed, 7253 insertions(+), 4112 deletions(-) rewrite WINGs/wfont.c (87%) create mode 100644 WINGs/wfont_noxft.c create mode 100644 WINGs/wfont_wchar.c create mode 100644 util/convertfonts.c rewrite wrlib/x86_specific.c (80%) diff --git a/ChangeLog b/ChangeLog index 8ed04745..a8c8ade7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -110,7 +110,6 @@ Changes since version 0.80.2: (Marcelo E. Magallon ) - Do not use the disabled clip color for the clip's workspace navigation arrows when the clip is collapsed (it made them look like disabled) -- Fixed the 'focus flicker' problem, seen with GTK2 applications. - Fixed bug with incorrect un-escaping if there is a dot in wm_class. - Updated Catalan translations (Ernest Adrogue ) - Updated Spanish translation of WPrefs (Alberto Gimenez ) @@ -123,12 +122,42 @@ Changes since version 0.80.2: appicon when a KDE3 application opens a config panel. - Updated slovak translation (Jan Tomka ) - Added xdnd v3 support in WINGs (Sylvain Reynal ) +- Check whether libXft is at least version 2.1.2 else refuse to compile. +- Fixed bug in icon chooser dialog that could cause a segmentation fault + in some cases (Pascal Hofstee ) +- Fixed crash in asm code in wrlib, with new versions of gcc. +- Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly + used the r, g, b fields in the conversion. +- Fixed x86 ASM code in wrlib to work on 64 bit architectures. +- Fixed the focus flicker seen with some apps (notably gtk2) + (Alexey Spiridonov ) +- Fixed all crashing bugs that were generated by wmaker starting with the + WMState file missing. +- Added NetWM support (a modified version of the patch originaly written + by Peter Zijlstra ) +- Applied patch to enhance the Virtual Desktop behaviour, and to integrate + it with the NetWM code (Peter Zijlstra ) +- Applied a few xinerama and placement fixes (Peter Zijlstra + ) +- Fixed memory leak in dock code. +- Fixed and enhanced the text wrapping in WINGs. +- Fixed the layout of some elements in WPrefs.app +- Added workaround for aplications that don't set the required hints on the + client leader window, but they set them on normal windows (observer with + KDE 3.3.0 mainly). This will allow these apps to get an appicon again. + (they should be fixed still) +- Added workaround for applications that do not set a command with + XSetCommand(), but instead they set the _NET_WM_PID property. This works + with operating systems that offer a /proc interface similar to what linux + has. (This also is to fix problems with KDE 3.3.0 apps, but not only them). +- Fixed bug with autostart and exit scripts not being executed if user + GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT) Changes since version 0.80.1: ............................. -- Fixed a buffer overflow when allocating an RImage struct. +- Fixed a buffer overflow when allocating a RImage struct. Changes since version 0.80.0: diff --git a/TODO b/TODO index b5663c13..31abecb6 100644 --- a/TODO +++ b/TODO @@ -61,4 +61,3 @@ sample implementation (twm?) it might be supported. Maybe dtwm supports it? I dont know... - diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 6dcd582c..51b93469 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -1,8 +1,8 @@ Changes since wmaker 0.80.1: ............................ -- added WMSetConnectionShutdownOnClose() -- added an extra member to the ConnectionDelegate: canResumeSending +- Added WMSetConnectionShutdownOnClose() +- Added an extra member to the ConnectionDelegate: canResumeSending see NEWS for details. - WMDrawString() and WMDrawImageString() now take WMColor instead of GC as arguments. WMDrawImageString() receives 2 colors (text & background). @@ -49,12 +49,13 @@ Changes since wmaker 0.80.1: - Fixed a memleak in the file panel. - Double/triple-click selection in text widgets (Vitaly Ovtchinnikov ) -- fixed bug in tableview (clicked row callback got incorrect row) +- Fixed bug in tableview (clicked row callback got incorrect row) (Carlos Torres ) - Fixed bug in resizing a scrollview - Fixed bug with wrong text wrapping (Alexey Voinov ) - Added wmkrect() - Added xdnd v3 support (Sylvain Reynal ) +- Fixed and enhanced text wrapping. Changes since wmaker 0.80.0: diff --git a/WINGs/Examples/puzzle.c b/WINGs/Examples/puzzle.c index b99da4e0..22f2249c 100644 --- a/WINGs/Examples/puzzle.c +++ b/WINGs/Examples/puzzle.c @@ -21,7 +21,8 @@ int MoveCount; int WinSize = 120; -Bool CheckWin(void) +Bool +CheckWin(void) { int i; @@ -34,15 +35,17 @@ Bool CheckWin(void) } -void MoveButton(int button, int x, int y) +void +MoveButton(int button, int x, int y) { WMMoveWidget(Button[button], x*(WinSize/Size), y*(WinSize/Size)); } -Bool SlideButton(int button) +Bool +SlideButton(int button) { - int x, y, done = 0; + int x=0, y=0, done = 0; /* locate the button */ for (y = 0; y < Size; y++) { diff --git a/WINGs/Extras/Makefile.am b/WINGs/Extras/Makefile.am index c3a693f8..63119aec 100644 --- a/WINGs/Extras/Makefile.am +++ b/WINGs/Extras/Makefile.am @@ -22,6 +22,7 @@ libExtraWINGs_a_SOURCES = \ wtableview.h \ wtabledelegates.h +AM_CFLAGS = -fno-strict-aliasing INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/WINGs \ -DRESOURCE_PATH=\"$(datadir)/WINGs\" @HEADER_SEARCH_PATH@ -DDEBUG diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 9df6a54d..3ff80d6e 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -108,7 +108,9 @@ libWUtil_a_SOURCES = \ wutil.c -AM_CPPFLAGS = @CPPFLAGS@ -DLOCALEDIR=\"$(NLSDIR)\" +AM_CPPFLAGS = -DLOCALEDIR=\"$(NLSDIR)\" + +AM_CFLAGS = -fno-strict-aliasing INCLUDES = -I$(top_srcdir)/WINGs/WINGs -I$(top_srcdir)/wrlib -I$(top_srcdir)/src \ -DRESOURCE_PATH=\"$(datadir)/WINGs\" @XFTFLAGS@ @HEADER_SEARCH_PATH@ -DDEBUG diff --git a/WINGs/Tests/wtest.c b/WINGs/Tests/wtest.c index d180a6a9..7339061e 100644 --- a/WINGs/Tests/wtest.c +++ b/WINGs/Tests/wtest.c @@ -116,14 +116,14 @@ testFrame(WMScreen *scr) } -static void +/*static void resizedWindow(void *self, WMNotification *notif) { WMView *view = (WMView*)WMGetNotificationObject(notif); WMSize size = WMGetViewSize(view); WMResizeWidget((WMWidget*)self, size.width, size.height); -} +}*/ void testBox(WMScreen *scr) @@ -609,7 +609,8 @@ testText(WMScreen *scr) WMFont *font, *ifont; font = WMDefaultSystemFont(scr); - ifont = WMCopyFontWithStyle(scr, font, WFSEmphasized); + //ifont = WMCopyFontWithStyle(scr, font, WFSEmphasized); + ifont = WMCreateFont(scr, "verdana,sans:pixelsize=12:italic"); if (ifont) { WMSetTextDefaultFont(text, ifont); WMReleaseFont(ifont); @@ -619,7 +620,7 @@ testText(WMScreen *scr) WMReleaseFont(font); } - if(file) { + if (file) { char buf[1024]; WMFreezeText(text); @@ -1042,6 +1043,7 @@ main(int argc, char **argv) testColorPanel(scr); + testFrame(scr); #if 0 testBox(scr); diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index f3805b04..d08936b9 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -1834,12 +1834,11 @@ void WMShowFontPanel(WMFontPanel *panel); void WMHideFontPanel(WMFontPanel *panel); -void WMSetFontPanelAction(WMFontPanel *panel, WMAction2 *action, void *data); +void WMFreeFontPanel(WMFontPanel *panel); -void WMSetFontPanelFont(WMFontPanel *panel, WMFont *font); +void WMSetFontPanelAction(WMFontPanel *panel, WMAction2 *action, void *data); -/* you can free the returned string */ -char* WMGetFontPanelFontName(WMFontPanel *panel); +void WMSetFontPanelFont(WMFontPanel *panel, char *fontName); WMFont* WMGetFontPanelFont(WMFontPanel *panel); diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 7f42ed60..673e9c54 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -22,19 +22,14 @@ extern "C" { #endif /* __cplusplus */ -#define DOUBLE_BUFFER - +#define DOUBLE_BUFFER 1 #define WC_UserWidget 128 +#define SCROLLER_WIDTH 20 - -#define SCROLLER_WIDTH 20 - - - -#define XDND_VERSION 4 +#define XDND_VERSION 4 typedef struct W_Application { diff --git a/WINGs/configuration.c b/WINGs/configuration.c index 0baf60bf..7d8d0c15 100644 --- a/WINGs/configuration.c +++ b/WINGs/configuration.c @@ -14,10 +14,6 @@ _WINGsConfiguration WINGsConfiguration; #define BOLD_SYSTEM_FONT "-*-helvetica-bold-r-normal-*-%d-*-*-*-*-*-*-*,-*-*-bold-r-*-*-%d-*-*-*-*-*-*-*" -#define XFTSYSTEM_FONT "-*-arial-medium-r-normal-*-%d-*-*-*-*-*-*-*" - -#define XFTBOLD_SYSTEM_FONT "-*-arial-bold-r-normal-*-%d-*-*-*-*-*-*-*" - #define FLOPPY_PATH "/floppy" @@ -45,6 +41,7 @@ getButtonWithName(const char *name, unsigned defaultButton) } +// fix this static Bool missingOrInvalidXLFD(char *xlfd) { diff --git a/WINGs/dragcommon.c b/WINGs/dragcommon.c index 77053783..c877d2a4 100644 --- a/WINGs/dragcommon.c +++ b/WINGs/dragcommon.c @@ -193,14 +193,15 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) WMDraggingInfo *info = &scr->dragInfo; Atom messageType = event->message_type; - char* msgTypeName = XGetAtomName(scr->display, messageType); - #ifdef XDND_DEBUG + { + char* msgTypeName = XGetAtomName(scr->display, messageType); - if (msgTypeName != NULL) - printf("event type = %s\n", msgTypeName); - else - printf("pb with event type !\n"); + if (msgTypeName != NULL) + printf("event type = %s\n", msgTypeName); + else + printf("pb with event type !\n"); + } #endif diff --git a/WINGs/dragdestination.c b/WINGs/dragdestination.c index e982dacf..03dcd9bd 100644 --- a/WINGs/dragdestination.c +++ b/WINGs/dragdestination.c @@ -79,7 +79,7 @@ createDropDataArray(WMArray *requiredTypes) static WMArray* getTypesFromTypeList(WMScreen *scr, Window sourceWin) { - WMDraggingInfo *info = &scr->dragInfo; + /* // WMDraggingInfo *info = &scr->dragInfo;*/ Atom dataType; Atom* typeAtomList; WMArray* typeList; @@ -365,7 +365,6 @@ W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo *info, WMView *toplevel, XClientMessageEvent *event) { WMScreen *scr = W_VIEW_SCREEN(toplevel); - int i,j, typesCount; if (XDND_DEST_INFO(info) == NULL) initDestinationDragInfo(info); @@ -609,7 +608,7 @@ static void sendAllowedAction(WMView *destView, Atom action) { WMScreen *scr = W_VIEW_SCREEN(destView); - WMPoint destPos = WMGetViewScreenPosition(destView); + /* // WMPoint destPos = WMGetViewScreenPosition(destView); */ WMSize destSize = WMGetViewSize(destView); int destX, destY; Window foo; diff --git a/WINGs/dragsource.c b/WINGs/dragsource.c index b08ee783..3b26499c 100644 --- a/WINGs/dragsource.c +++ b/WINGs/dragsource.c @@ -425,6 +425,8 @@ sendEnterMessage(WMDraggingInfo *info) } +// this functon doesn't return something in all cases. +// control reaches end of non-void function. fix this -Dan static Bool sendPositionMessage(WMDraggingInfo *info, WMPoint *mousePos) { @@ -740,7 +742,6 @@ isXdndAware(WMScreen *scr, Window win) int format; unsigned long count, remain; unsigned char *winXdndVersion; - unsigned char *proxy; if (win == None) return False; @@ -876,7 +877,7 @@ initMotionProcess(WMView *view, WMDraggingInfo *info, static void processMotion(WMDraggingInfo *info, Window windowUnderDrag, WMPoint *mousePos) { - WMScreen *scr = sourceScreen(info); + /* // WMScreen *scr = sourceScreen(info); */ Window newDestination = findDestination(info, mousePos); W_DragSourceStopTimer(); @@ -1058,6 +1059,7 @@ traceStatusMsg(Display *dpy, XClientMessageEvent *statusEvent) #endif +static void storeDropAction(WMDraggingInfo *info, Atom destAction) { WMView* sourceView = XDND_SOURCE_VIEW(info); diff --git a/WINGs/python/WINGs.py b/WINGs/python/WINGs.py index 3d008316..dbdccde2 100644 --- a/WINGs/python/WINGs.py +++ b/WINGs/python/WINGs.py @@ -26,10 +26,11 @@ class WMTimer: self._o = wings.pyWMAddPersistentTimerHandler(milliseconds, (callback, cdata)) else: self._o = wings.pyWMAddTimerHandler(milliseconds, (callback, cdata)) + self.__WMDeleteTimerHandler = wings.pyWMDeleteTimerHandler def __del__(self): - wings.pyWMDeleteTimerHandler(self._o) - #delete = __del__ + self.__WMDeleteTimerHandler(self._o) + class WMPersistentTimer(WMTimer): def __init__(self, milliseconds, callback, cdata=None): @@ -87,14 +88,15 @@ class WMView: class WMWidget(WMView): def __init__(self): - self._o = None if self.__class__ == WMWidget: raise Error, "a WMWidget can't be instantiated directly" + self._o = None + self.__WMDestroyWidget = wings.WMDestroyWidget def __del__(self): - if (self._o != None): - wings.WMDestroyWidget(self._o) - + if self._o is not None: + self.__WMDestroyWidget(self._o) + def resize(self, width, height): wings.WMResizeWidget(self._o, width, height) diff --git a/WINGs/userdefaults.c b/WINGs/userdefaults.c index b6744070..566f8e0e 100644 --- a/WINGs/userdefaults.c +++ b/WINGs/userdefaults.c @@ -272,7 +272,7 @@ WMGetStandardUserDefaults(void) defaults = wmalloc(sizeof(WMUserDefaults)); memset(defaults, 0, sizeof(WMUserDefaults)); - defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL); + defaults->defaults = WMCreatePLDictionary(NULL, NULL); defaults->searchList = wmalloc(sizeof(WMPropList*)*3); @@ -293,7 +293,7 @@ WMGetStandardUserDefaults(void) domain = WMReadPropListFromFile(path); if (!domain) - domain = WMCreatePLDictionary(NULL, NULL, NULL); + domain = WMCreatePLDictionary(NULL, NULL); if (path) wfree(path); @@ -314,7 +314,7 @@ WMGetStandardUserDefaults(void) wfree(path); if (!domain) - domain = WMCreatePLDictionary(NULL, NULL, NULL); + domain = WMCreatePLDictionary(NULL, NULL); if (domain) WMPutInPLDictionary(defaults->defaults, key, domain); @@ -367,7 +367,7 @@ WMGetDefaultsFromPath(char *path) defaults = wmalloc(sizeof(WMUserDefaults)); memset(defaults, 0, sizeof(WMUserDefaults)); - defaults->defaults = WMCreatePLDictionary(NULL, NULL, NULL); + defaults->defaults = WMCreatePLDictionary(NULL, NULL); defaults->searchList = wmalloc(sizeof(WMPropList*)*2); @@ -387,7 +387,7 @@ WMGetDefaultsFromPath(char *path) domain = WMReadPropListFromFile(path); if (!domain) - domain = WMCreatePLDictionary(NULL, NULL, NULL); + domain = WMCreatePLDictionary(NULL, NULL); defaults->path = wstrdup(path); diff --git a/WINGs/wevent.c b/WINGs/wevent.c index 28cd4e0e..f1a62a38 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -66,8 +66,8 @@ static WMEventHook *extraEventHandler=NULL; * */ void - WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc, - void *clientData) +WMCreateEventHandler(WMView *view, unsigned long mask, WMEventProc *eventProc, + void *clientData) { W_EventHandler *hPtr; WMArrayIterator iter; diff --git a/WINGs/wfont.c b/WINGs/wfont.c dissimilarity index 87% index 6acc278d..89742f8d 100644 --- a/WINGs/wfont.c +++ b/WINGs/wfont.c @@ -1,1661 +1,389 @@ - -#include "wconfig.h" - -#ifdef XFT -# include -# ifdef HAVE_WCHAR_H -# include -# endif -# include -#endif - -#include "WINGsP.h" - -#include -#include -#include - - -#ifdef XFT - -#if defined(HAVE_MBSNRTOWCS) - -static size_t -wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) -{ - mbstate_t ps; - size_t n; - - memset(&ps, 0, sizeof(mbstate_t)); - n = mbsnrtowcs(dest, src, nbytes, len, &ps); - if (n!=(size_t)-1 && *src) { - *src -= ps.__count; - } - - return n; -} - -#elif defined(HAVE_MBRTOWC) - -// This is 8 times slower than the version above. -static size_t -wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) -{ - mbstate_t ps; - const char *ptr; - size_t n; - int nb; - - if (nbytes==0) - return 0; - - memset(&ps, 0, sizeof(mbstate_t)); - - if (dest == NULL) { - for (ptr=*src, n=0; nbytes>0; n++) { - nb = mbrtowc(NULL, ptr, nbytes, &ps); - if (nb == -1) { - return ((size_t)-1); - } else if (nb==0 || nb==-2) { - return n; - } - ptr += nb; - nbytes -= nb; - } - } - - for (ptr=*src, n=0; n0; n++, dest++) { - nb = mbrtowc(dest, ptr, nbytes, &ps); - if (nb == -2) { - *src = ptr; - return n; - } else if (nb == -1) { - *src = ptr; - return ((size_t)-1); - } else if (nb == 0) { - *src = NULL; - return n; - } - ptr += nb; - nbytes -= nb; - } - - *src = ptr; - return n; -} - -#else - -// Not only 8 times slower than the version based on mbsnrtowcs -// but also this version is not thread safe nor reentrant - -static size_t -wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) -{ - const char *ptr; - size_t n; - int nb; - - if (nbytes==0) - return 0; - - mbtowc(NULL, NULL, 0); /* reset shift state */ - - if (dest == NULL) { - for (ptr=*src, n=0; nbytes>0; n++) { - nb = mbtowc(NULL, ptr, nbytes); - if (nb == -1) { - mbtowc(NULL, NULL, 0); - nb = mbtowc(NULL, ptr, strlen(ptr)); - return (nb == -1 ? (size_t)-1 : n); - } else if (nb==0) { - return n; - } - ptr += nb; - nbytes -= nb; - } - } - - for (ptr=*src, n=0; n0; n++, dest++) { - nb = mbtowc(dest, ptr, nbytes); - if (nb == -1) { - mbtowc(NULL, NULL, 0); - nb = mbtowc(NULL, ptr, strlen(ptr)); - *src = ptr; - return (nb == -1 ? (size_t)-1 : n); - } else if (nb == 0) { - *src = NULL; - return n; - } - ptr += nb; - nbytes -= nb; - } - - *src = ptr; - return n; -} - -#endif - - -static Bool -alreadyHasStringValue(XftPattern *pattern, const char *object, char *value) -{ - XftResult r; - char *s; - int id; - - if (!value || value[0]==0) - return True; - - id = 0; - while ((r=XftPatternGetString(pattern, object, id, &s))==XftResultMatch) { - if (strcasecmp(value, s) == 0) { - return True; - } - id++; - } - - return False; -} - - -// check if to add a fallback size too. -Dan -// also handle an xlfd with %d for size? -static char* -makeFontOfSize(char *font, int size, char *fallback) -{ - FcPattern *pattern; - char *result; - - pattern = XftNameParse(font); - XftPatternDel(pattern, "pixelsize"); - XftPatternAddDouble(pattern, "pixelsize", (double)size); - - if (fallback) { - if (!alreadyHasStringValue(pattern, "family", fallback)) { - XftPatternAddString(pattern, "family", fallback); - } - } - - result = FcNameUnparse(pattern); - FcPatternDestroy(pattern); - - return result; -} - - -WMFont* -WMCreateFont(WMScreen *scrPtr, char *fontName) -{ - WMFont *font; - Display *display = scrPtr->display; - char *fname, *ptr; - - /* This is for back-compat (to allow reading of old xlfd descriptions) */ - if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) { - // warn for deprecation - fname = wmalloc(ptr - fontName + 1); - strncpy(fname, fontName, ptr - fontName); - fname[ptr - fontName] = 0; - } else { - fname = wstrdup(fontName); - } - - font = WMHashGet(scrPtr->fontCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - memset(font, 0, sizeof(WMFont)); - - font->screen = scrPtr; - - // remove - printf("WMCreateFont: %s\n", fname); - - if (fname[0] == '-') { - // Backward compat thing. Remove in a later version - font->font = XftFontOpenXlfd(display, scrPtr->screen, fname); - } else { - font->font = XftFontOpenName(display, scrPtr->screen, fname); - } - if (!font->font) { - wfree(font); - wfree(fname); - return NULL; - } - font->height = font->font->ascent+font->font->descent; - font->y = font->font->ascent; - - font->refCount = 1; - - font->name = fname; - - assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL); - - return font; -} - - -WMFont* -WMRetainFont(WMFont *font) -{ - wassertrv(font!=NULL, NULL); - - font->refCount++; - - return font; -} - - -void -WMReleaseFont(WMFont *font) -{ - wassertr(font!=NULL); - - font->refCount--; - if (font->refCount < 1) { - XftFontClose(font->screen->display, font->font); - if (font->name) { - WMHashRemove(font->screen->fontCache, font->name); - wfree(font->name); - } - wfree(font); - } -} - - -Bool -WMIsAntialiasingEnabled(WMScreen *scrPtr) -{ - return scrPtr->antialiasedText; -} - - -unsigned int -WMFontHeight(WMFont *font) -{ - wassertrv(font!=NULL, 0); - - return font->height; -} - - -char* -WMGetFontName(WMFont *font) -{ - wassertrv(font!=NULL, NULL); - - return font->name; -} - - -WMFont* -WMDefaultSystemFont(WMScreen *scrPtr) -{ - return WMRetainFont(scrPtr->normalFont); -} - - -WMFont* -WMDefaultBoldSystemFont(WMScreen *scrPtr) -{ - return WMRetainFont(scrPtr->boldFont); -} - - -WMFont* -WMSystemFontOfSize(WMScreen *scrPtr, int size) -{ - WMFont *font; - char *fontSpec; - - fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans"); - - font = WMCreateFont(scrPtr, fontSpec); - - if (!font) { - wwarning(_("could not load font %s."), fontSpec); - } - - wfree(fontSpec); - - return font; -} - - -WMFont* -WMBoldSystemFontOfSize(WMScreen *scrPtr, int size) -{ - WMFont *font; - char *fontSpec; - - fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans"); - - font = WMCreateFont(scrPtr, fontSpec); - - if (!font) { - wwarning(_("could not load font %s."), fontSpec); - } - - wfree(fontSpec); - - return font; -} - - -int -WMWidthOfString(WMFont *font, char *text, int length) -{ - XGlyphInfo extents; - - wassertrv(font!=NULL, 0); - wassertrv(text!=NULL, 0); - - if (font->screen->useWideChar) { - wchar_t *wtext; - const char *mtext; - int len; - - wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); - mtext = text; - len = wmbsnrtowcs(wtext, &mtext, length, length); - if (len>0) { - wtext[len] = L'\0'; /* not really necessary here */ - XftTextExtents32(font->screen->display, font->font, - (XftChar32 *)wtext, len, &extents); - } else { - if (len==-1) { - wwarning(_("Conversion to widechar failed (possible " - "invalid multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - } - extents.xOff = 0; - } - wfree(wtext); - } else { - XftTextExtents8(font->screen->display, font->font, - (XftChar8 *)text, length, &extents); - } - - return extents.xOff; /* don't ask :P */ -} - - - -void -WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, - int x, int y, char *text, int length) -{ - XftColor xftcolor; - - wassertr(font!=NULL); - - xftcolor.color.red = color->color.red; - xftcolor.color.green = color->color.green; - xftcolor.color.blue = color->color.blue; - xftcolor.color.alpha = color->alpha;; - xftcolor.pixel = W_PIXEL(color); - - XftDrawChange(scr->xftdraw, d); - - if (font->screen->useWideChar) { - wchar_t *wtext; - const char *mtext; - int len; - - wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); - mtext = text; - len = wmbsnrtowcs(wtext, &mtext, length, length); - if (len>0) { - XftDrawString32(scr->xftdraw, &xftcolor, font->font, - x, y + font->y, (XftChar32*)wtext, len); - } else if (len==-1) { - wwarning(_("Conversion to widechar failed (possible invalid " - "multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - /* we can draw normal text, or we can draw as much widechar - * text as was already converted until the error. go figure */ - /*XftDrawString8(scr->xftdraw, &xftcolor, font->font, - x, y + font->y, (XftChar8*)text, length);*/ - } - wfree(wtext); - } else { - XftDrawString8(scr->xftdraw, &xftcolor, font->font, - x, y + font->y, (XftChar8*)text, length); - } -} - - -void -WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background, - WMFont *font, int x, int y, char *text, int length) -{ - XftColor textColor; - XftColor bgColor; - - wassertr(font!=NULL); - - textColor.color.red = color->color.red; - textColor.color.green = color->color.green; - textColor.color.blue = color->color.blue; - textColor.color.alpha = color->alpha;; - textColor.pixel = W_PIXEL(color); - - bgColor.color.red = background->color.red; - bgColor.color.green = background->color.green; - bgColor.color.blue = background->color.blue; - bgColor.color.alpha = background->alpha;; - bgColor.pixel = W_PIXEL(background); - - XftDrawChange(scr->xftdraw, d); - - XftDrawRect(scr->xftdraw, &bgColor, x, y, - WMWidthOfString(font, text, length), - font->height); - - if (font->screen->useWideChar) { - wchar_t *wtext; - const char *mtext; - int len; - - mtext = text; - wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); - len = wmbsnrtowcs(wtext, &mtext, length, length); - if (len>0) { - XftDrawString32(scr->xftdraw, &textColor, font->font, - x, y + font->y, (XftChar32*)wtext, len); - } else if (len==-1) { - wwarning(_("Conversion to widechar failed (possible invalid " - "multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - /* we can draw normal text, or we can draw as much widechar - * text as was already converted until the error. go figure */ - /*XftDrawString8(scr->xftdraw, &textColor, font->font, - x, y + font->y, (XftChar8*)text, length);*/ - } - wfree(wtext); - } else { - XftDrawString8(scr->xftdraw, &textColor, font->font, - x, y + font->y, (XftChar8*)text, length); - } -} - - -WMFont* -WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style) -{ - FcPattern *pattern; - WMFont *copy; - char *name; - - if (!font) - return NULL; - - pattern = XftNameParse(WMGetFontName(font)); - switch (style) { - case WFSNormal: - XftPatternDel(pattern, "weight"); - XftPatternDel(pattern, "slant"); - XftPatternAddString(pattern, "weight", "medium"); - XftPatternAddString(pattern, "slant", "roman"); - break; - case WFSBold: - XftPatternDel(pattern, "weight"); - XftPatternAddString(pattern, "weight", "bold"); - break; - case WFSEmphasized: - XftPatternDel(pattern, "slant"); - XftPatternAddString(pattern, "slant", "italic"); - XftPatternAddString(pattern, "slant", "oblique"); - break; - case WFSBoldEmphasized: - XftPatternDel(pattern, "weight"); - XftPatternDel(pattern, "slant"); - XftPatternAddString(pattern, "weight", "bold"); - XftPatternAddString(pattern, "slant", "italic"); - XftPatternAddString(pattern, "slant", "oblique"); - break; - } - - name = FcNameUnparse(pattern); - copy = WMCreateFont(scrPtr, name); - FcPatternDestroy(pattern); - wfree(name); - - return copy; -} - - -#else /* No XFT support */ - - -static char *makeFontSetOfSize(char *fontset, int size); - - - -/* XLFD pattern matching */ -static char* -getElementFromXLFD(const char *xlfd, int index) -{ - const char *p = xlfd; - while (*p != 0) { - if (*p == '-' && --index == 0) { - const char *end = strchr(p + 1, '-'); - char *buf; - size_t len; - if (end == 0) end = p + strlen(p); - len = end - (p + 1); - buf = wmalloc(len); - memcpy(buf, p + 1, len); - buf[len] = 0; - return buf; - } - p++; - } - return strdup("*"); -} - - -/* XLFD pattern matching */ -static char* -generalizeXLFD(const char *xlfd) -{ - char *buf; - int len; - char *weight = getElementFromXLFD(xlfd, 3); - char *slant = getElementFromXLFD(xlfd, 4); - char *pxlsz = getElementFromXLFD(xlfd, 7); - -#define Xstrlen(A) ((A)?strlen(A):0) - len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60; -#undef Xstrlen - - buf = wmalloc(len + 1); - snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*," - "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*", - xlfd, weight, slant, pxlsz, pxlsz); - - wfree(pxlsz); - wfree(slant); - wfree(weight); - - return buf; -} - -/* XLFD pattern matching */ -static XFontSet -W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing, - int *nmissing, char **def_string) -{ - XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); - - if (fs != NULL && *nmissing == 0) return fs; - - /* for non-iso8859-1 language and iso8859-1 specification - (this fontset is only for pattern analysis) */ - if (fs == NULL) { - if (*nmissing != 0) XFreeStringList(*missing); - setlocale(LC_CTYPE, "C"); - fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); - setlocale(LC_CTYPE, ""); - } - - /* make XLFD font name for pattern analysis */ - if (fs != NULL) { - XFontStruct **fontstructs; - char **fontnames; - if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0) - xlfd = fontnames[0]; - } - - xlfd = generalizeXLFD(xlfd); - - if (*nmissing != 0) XFreeStringList(*missing); - if (fs != NULL) XFreeFontSet(dpy, fs); - - fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); - - wfree(xlfd); - return fs; -} - - -static char* -xlfdFromFontName(char *fontName, Bool antialiased) -{ - char *systemFont, *boldSystemFont; - char *font; - int size; - - if (antialiased) { - systemFont = WINGsConfiguration.antialiasedSystemFont; - boldSystemFont = WINGsConfiguration.antialiasedBoldSystemFont; - } else { - systemFont = WINGsConfiguration.systemFont; - boldSystemFont = WINGsConfiguration.boldSystemFont; - } - - size = WINGsConfiguration.defaultFontSize; - - if (strcmp(fontName, "SystemFont")==0) { - font = systemFont; - size = WINGsConfiguration.defaultFontSize; - } else if (strncmp(fontName, "SystemFont-", 11)==0) { - font = systemFont; - if (sscanf(&fontName[11], "%i", &size)!=1) { - size = WINGsConfiguration.defaultFontSize; - wwarning(_("Invalid size specification '%s' in %s. " - "Using default %d\n"), &fontName[11], fontName, size); - } - } else if (strcmp(fontName, "BoldSystemFont")==0) { - font = boldSystemFont; - size = WINGsConfiguration.defaultFontSize; - } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) { - font = boldSystemFont; - if (sscanf(&fontName[15], "%i", &size)!=1) { - size = WINGsConfiguration.defaultFontSize; - wwarning(_("Invalid size specification '%s' in %s. " - "Using default %d\n"), &fontName[15], fontName, size); - } - } else { - font = NULL; - } - - return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName)); -} - - -WMFont* -WMCreateFontSet(WMScreen *scrPtr, char *fontName) -{ - WMFont *font; - Display *display = scrPtr->display; - char **missing; - int nmissing = 0; - char *defaultString; - char *fname; - XFontSetExtents *extents; - - fname = xlfdFromFontName(fontName, False); - - font = WMHashGet(scrPtr->fontSetCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - memset(font, 0, sizeof(WMFont)); - - font->notFontSet = 0; - font->antialiased = 0; - - font->screen = scrPtr; - - font->font.set = W_CreateFontSetWithGuess(display, fname, &missing, - &nmissing, &defaultString); - if (nmissing > 0 && font->font.set) { - int i; - - wwarning(_("the following character sets are missing in %s:"), fname); - for (i = 0; i < nmissing; i++) { - wwarning(missing[i]); - } - XFreeStringList(missing); - if (defaultString) - wwarning(_("the string \"%s\" will be used in place of any characters from those sets."), - defaultString); - } - if (!font->font.set) { - wfree(font); - wfree(fname); - return NULL; - } - - extents = XExtentsOfFontSet(font->font.set); - - font->height = extents->max_logical_extent.height; - font->y = font->height - (font->height + extents->max_logical_extent.y); - - font->refCount = 1; - - font->name = fname; - - assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL); - - return font; -} - - - -WMFont* -WMCreateNormalFont(WMScreen *scrPtr, char *fontName) -{ - WMFont *font; - Display *display = scrPtr->display; - char *fname, *ptr; - - fontName = xlfdFromFontName(fontName, False); - - if ((ptr = strchr(fontName, ','))) { - fname = wmalloc(ptr - fontName + 1); - strncpy(fname, fontName, ptr - fontName); - fname[ptr - fontName] = 0; - } else { - fname = wstrdup(fontName); - } - - wfree(fontName); - - font = WMHashGet(scrPtr->fontCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - memset(font, 0, sizeof(WMFont)); - - font->notFontSet = 1; - font->antialiased = 0; - - font->screen = scrPtr; - - font->font.normal = XLoadQueryFont(display, fname); - if (!font->font.normal) { - wfree(font); - wfree(fname); - return NULL; - } - font->height = font->font.normal->ascent+font->font.normal->descent; - font->y = font->font.normal->ascent; - - font->refCount = 1; - - font->name = fname; - - assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL); - - return font; -} - - -WMFont* -WMCreateAntialiasedFont(WMScreen *scrPtr, char *fontName) -{ -#ifdef XFT - WMFont *font; - Display *display = scrPtr->display; - char *fname, *ptr; - - fontName = xlfdFromFontName(fontName, True); - - if ((ptr = strchr(fontName, ','))) { - fname = wmalloc(ptr - fontName + 1); - strncpy(fname, fontName, ptr - fontName); - fname[ptr - fontName] = 0; - } else { - fname = wstrdup(fontName); - } - - wfree(fontName); - - font = WMHashGet(scrPtr->xftFontCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - memset(font, 0, sizeof(WMFont)); - - font->notFontSet = 1; - font->antialiased = 1; - - font->screen = scrPtr; - - /* Xft sux. Loading a font with an invalid XLFD will give strange results - * sometimes without returning any warning or error. - * However Xft's idea of what font is invalid is quite strange: - * 1. If the XLFD doesn't have all its fields present will fail and - * return NULL. - * 2. If all fields are present, but hold invalid values then it will: - * a. If family is invalid, will load a default font without warning. - * b. If the font size is invalid (non-numerical) it will fail and - * return NULL. - * c. If other fields are invalid, will load the font specified by - * the valid family name, ignoring any invalid fields. It will - * use a default medium weight and a default roman slant if they - * are invalid. - */ - printf("%s\n", fname); - if (fname[0] == '-') { - font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname); - } else { - font->font.xft = XftFontOpenName(display, scrPtr->screen, fname); - } - if (!font->font.xft) { - wfree(font); - wfree(fname); - return NULL; - } - font->height = font->font.xft->ascent+font->font.xft->descent; - font->y = font->font.xft->ascent; - - font->refCount = 1; - - font->name = fname; - - assert(WMHashInsert(scrPtr->xftFontCache, font->name, font)==NULL); - - return font; -#else - return NULL; -#endif -} - - -WMFont* -WMCreateAntialiasedFontSet(WMScreen *scrPtr, char *fontName) -{ -#ifdef XFT - WMFont *font; - Display *display = scrPtr->display; - char *fname, *ptr; - - fontName = xlfdFromFontName(fontName, True); - - if ((ptr = strchr(fontName, ','))) { - fname = wmalloc(ptr - fontName + 1); - strncpy(fname, fontName, ptr - fontName); - fname[ptr - fontName] = 0; - } else { - fname = wstrdup(fontName); - } - - wfree(fontName); - - font = WMHashGet(scrPtr->xftFontSetCache, fname); - if (font) { - WMRetainFont(font); - wfree(fname); - return font; - } - - font = wmalloc(sizeof(WMFont)); - memset(font, 0, sizeof(WMFont)); - - font->notFontSet = 0; - font->antialiased = 1; - - font->screen = scrPtr; - - /* Xft sux. Loading a font with an invalid XLFD will give strange results - * sometimes without returning any warning or error. - * However Xft's idea of what font is invalid is quite strange: - * 1. If the XLFD doesn't have all its fields present will fail and - * return NULL. - * 2. If all fields are present, but hold invalid values then it will: - * a. If family is invalid, will load a default font without warning. - * b. If the font size is invalid (non-numerical) it will fail and - * return NULL. - * c. If other fields are invalid, will load the font specified by - * the valid family name, ignoring any invalid fields. It will - * use a default medium weight and a default roman slant if they - * are invalid. - */ - if (fname[0] == '-') { - font->font.xft = XftFontOpenXlfd(display, scrPtr->screen, fname); - } else { - font->font.xft = XftFontOpenName(display, scrPtr->screen, fname); - } - if (!font->font.xft) { - wfree(font); - wfree(fname); - return NULL; - } - font->height = font->font.xft->ascent+font->font.xft->descent; - font->y = font->font.xft->ascent; - - font->refCount = 1; - - font->name = fname; - - assert(WMHashInsert(scrPtr->xftFontSetCache, font->name, font)==NULL); - - return font; -#else - return NULL; -#endif -} - - -WMFont* -WMCreateFont(WMScreen *scrPtr, char *fontName) -{ - return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont); -} - - -WMFont* -WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags) -{ - Bool multiByte = scrPtr->useMultiByte; - Bool antialiased = scrPtr->antialiasedText; - WMFont *font; - - if (flags & WFFontSet) { - multiByte = True; - } else if (flags & WFNormalFont) { - multiByte = False; - } - if (flags & WFAntialiased) { - antialiased = True; - } else if (flags & WFNotAntialiased) { - antialiased = False; - } - - if (antialiased && multiByte) { - font = WMCreateAntialiasedFontSet(scrPtr, fontName); - /* If we cannot create an antialiased font set and antialiasing is - * not explicitly requested in flags, fallback to standard font sets */ - if (!font && (flags & WFAntialiased)==0) { - font = WMCreateFontSet(scrPtr, fontName); - } - } else if (antialiased) { - font = WMCreateAntialiasedFont(scrPtr, fontName); - /* If we cannot create an antialiased font and antialiasing is - * not explicitly requested in flags, fallback to normal font */ - if (!font && (flags & WFAntialiased)==0) { - font = WMCreateNormalFont(scrPtr, fontName); - } - } else if (multiByte) { - font = WMCreateFontSet(scrPtr, fontName); - } else { - font = WMCreateNormalFont(scrPtr, fontName); - } - - return font; -} - - -WMFont* -WMRetainFont(WMFont *font) -{ - wassertrv(font!=NULL, NULL); - - font->refCount++; - - return font; -} - - -void -WMReleaseFont(WMFont *font) -{ - wassertr(font!=NULL); - - font->refCount--; - if (font->refCount < 1) { - if (font->antialiased) { -#ifdef XFT - XftFontClose(font->screen->display, font->font.xft); -#else - assert(False); -#endif - } else if (font->notFontSet) { - XFreeFont(font->screen->display, font->font.normal); - } else { - XFreeFontSet(font->screen->display, font->font.set); - } - - if (font->name) { - if (font->antialiased && !font->notFontSet) { - WMHashRemove(font->screen->xftFontSetCache, font->name); - } else if (font->antialiased) { - WMHashRemove(font->screen->xftFontCache, font->name); - } else if (font->notFontSet) { - WMHashRemove(font->screen->fontCache, font->name); - } else { - WMHashRemove(font->screen->fontSetCache, font->name); - } - wfree(font->name); - } - wfree(font); - } -} - - -Bool -WMIsAntialiasingEnabled(WMScreen *scrPtr) -{ - return scrPtr->antialiasedText; -} - - -Bool -WMIsAntialiasedFont(WMFont *font) -{ - wassertrv(font!=NULL, False); - - return font->antialiased; -} - - -unsigned int -WMFontHeight(WMFont *font) -{ - wassertrv(font!=NULL, 0); - - return font->height; -} - - -char* -WMGetFontName(WMFont *font) -{ - wassertrv(font!=NULL, NULL); - - return font->name; -} - - -WMFont* -WMDefaultSystemFont(WMScreen *scrPtr) -{ - return WMRetainFont(scrPtr->normalFont); -} - - -WMFont* -WMDefaultBoldSystemFont(WMScreen *scrPtr) -{ - return WMRetainFont(scrPtr->boldFont); -} - - -static WMFont* -makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold) -{ - WMFont *font; - char *fontSpec, *xftFontSpec; - -#define WConf WINGsConfiguration - if (bold) { - fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size); - xftFontSpec = makeFontSetOfSize(WConf.antialiasedBoldSystemFont, size); - } else { - fontSpec = makeFontSetOfSize(WConf.systemFont, size); - xftFontSpec = makeFontSetOfSize(WConf.antialiasedSystemFont, size); - } -#undef WConf - - if (scrPtr->antialiasedText && scrPtr->useMultiByte) { - font = WMCreateAntialiasedFontSet(scrPtr, xftFontSpec); - } else if (scrPtr->antialiasedText) { - font = WMCreateAntialiasedFont(scrPtr, xftFontSpec); - } else if (scrPtr->useMultiByte) { - font = WMCreateFontSet(scrPtr, fontSpec); - } else { - font = WMCreateNormalFont(scrPtr, fontSpec); - } - - if (!font) { - if (scrPtr->antialiasedText && scrPtr->useMultiByte) { - // is arial a good fallback for multibyte? - wwarning(_("could not load font %s. Trying arial."), xftFontSpec); - if (bold) { - font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*"); - } else { - font = WMCreateAntialiasedFontSet(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*"); - } - if (!font) { - wwarning(_("could not load antialiased font set. Reverting to standard font sets.")); - font = WMCreateFontSet(scrPtr, fontSpec); - if (!font) { - wwarning(_("could not load FontSet %s. Trying fixed."), fontSpec); - font = WMCreateFontSet(scrPtr, "fixed"); - } - } - } else if (scrPtr->antialiasedText) { - wwarning(_("could not load font %s. Trying arial."), xftFontSpec); - if (bold) { - font = WMCreateAntialiasedFont(scrPtr, "-*-arial-bold-r-normal-*-12-*-*-*-*-*-*-*"); - } else { - font = WMCreateAntialiasedFont(scrPtr, "-*-arial-medium-r-normal-*-12-*-*-*-*-*-*-*"); - } - if (!font) { - wwarning(_("could not load antialiased fonts. Reverting to normal fonts.")); - font = WMCreateNormalFont(scrPtr, fontSpec); - if (!font) { - wwarning(_("could not load font %s. Trying fixed."), fontSpec); - font = WMCreateNormalFont(scrPtr, "fixed"); - } - } - } else if (scrPtr->useMultiByte) { - wwarning(_("could not load font set %s. Trying fixed."), fontSpec); - font = WMCreateFontSet(scrPtr, "fixed"); - if (!font) { - font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*"); - } - } else { - wwarning(_("could not load font %s. Trying fixed."), fontSpec); - font = WMCreateNormalFont(scrPtr, "fixed"); - } - if (!font) { - wwarning(_("could not load fixed font!")); - wfree(fontSpec); - wfree(xftFontSpec); - return NULL; - } - } - wfree(fontSpec); - wfree(xftFontSpec); - - return font; -} - - -WMFont* -WMSystemFontOfSize(WMScreen *scrPtr, int size) -{ - return makeSystemFontOfSize(scrPtr, size, False); -} - - -WMFont* -WMBoldSystemFontOfSize(WMScreen *scrPtr, int size) -{ - return makeSystemFontOfSize(scrPtr, size, True); -} - - -XFontSet -WMGetFontFontSet(WMFont *font) -{ - wassertrv(font!=NULL, NULL); - - if (!font->notFontSet && !font->antialiased) - return font->font.set; - - return NULL; -} - - -int -WMWidthOfString(WMFont *font, char *text, int length) -{ - wassertrv(font!=NULL, 0); - wassertrv(text!=NULL, 0); - - if (font->antialiased) { -#ifdef XFT - XGlyphInfo extents; - - if (!font->notFontSet) { - wchar_t *wtext; - char *mtext; - int len; - - /* Use mtext instead of text, because mbstrtowcs() alters it */ - mtext = text; - wtext = (wchar_t *)wmalloc(4*length+4); - /* pass a real ps instead of NULL below? for multithread safety - * as from manual page */ - len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL); - if (len>0) { - XftTextExtents32(font->screen->display, font->font.xft, - (XftChar32 *)wtext, len, &extents); - } else { - if (len==-1) { - wwarning(_("Conversion to widechar failed (possible " - "invalid multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - } - extents.xOff = 0; - } - wfree(wtext); - } else { - XftTextExtents8(font->screen->display, font->font.xft, - (XftChar8 *)text, length, &extents); - } - - return extents.xOff; /* don't ask :P */ -#else - wassertrv(False, 0); -#endif - } else if (font->notFontSet) { - return XTextWidth(font->font.normal, text, length); - } else { - XRectangle rect; - XRectangle AIXsucks; - - XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect); - - return rect.width; - } -} - - - -void -WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, - int x, int y, char *text, int length) -{ - wassertr(font!=NULL); - - if (font->antialiased) { -#ifdef XFT - XftColor xftcolor; - - xftcolor.color.red = color->color.red; - xftcolor.color.green = color->color.green; - xftcolor.color.blue = color->color.blue; - xftcolor.color.alpha = color->alpha;; - xftcolor.pixel = W_PIXEL(color); - - XftDrawChange(scr->xftdraw, d); - - if (!font->notFontSet) { - wchar_t *wtext; - char *mtext; - int len; - - /* Use mtext instead of text, because mbstrtowcs() alters it */ - mtext = text; - wtext = (wchar_t *)wmalloc(4*length+4); - len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL); - if (len>0) { - XftDrawString32(scr->xftdraw, &xftcolor, font->font.xft, - x, y + font->y, (XftChar32*)wtext, len); - } else if (len==-1) { - wwarning(_("Conversion to widechar failed (possible invalid " - "multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - /* we can draw normal text, or we can draw as much widechar - * text as was already converted until the error. go figure */ - /*XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft, - x, y + font->y, (XftChar8*)text, length);*/ - } - wfree(wtext); - } else { - XftDrawString8(scr->xftdraw, &xftcolor, font->font.xft, - x, y + font->y, (XftChar8*)text, length); - } -#else - wassertr(False); -#endif - } else if (font->notFontSet) { - XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid); - XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color)); - XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y, - text, length); - } else { - XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color)); - XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC, - x, y + font->y, text, length); - } -} - - -void -WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background, - WMFont *font, int x, int y, char *text, int length) -{ - wassertr(font!=NULL); - - if (font->antialiased) { -#ifdef XFT - XftColor textColor; - XftColor bgColor; - - textColor.color.red = color->color.red; - textColor.color.green = color->color.green; - textColor.color.blue = color->color.blue; - textColor.color.alpha = color->alpha;; - textColor.pixel = W_PIXEL(color); - - bgColor.color.red = background->color.red; - bgColor.color.green = background->color.green; - bgColor.color.blue = background->color.blue; - bgColor.color.alpha = background->alpha;; - bgColor.pixel = W_PIXEL(background); - - - XftDrawChange(scr->xftdraw, d); - - XftDrawRect(scr->xftdraw, &bgColor, x, y, - WMWidthOfString(font, text, length), font->height); - - if (!font->notFontSet) { - wchar_t *wtext; - char *mtext; - int len; - - /* Use mtext instead of text, because mbstrtowcs() alters it */ - mtext = text; - wtext = (wchar_t *)wmalloc(4*length+4); - len = mbsrtowcs(wtext, (const char **) &mtext, length, NULL); - if (len>0) { - XftDrawString32(scr->xftdraw, &textColor, font->font.xft, - x, y + font->y, (XftChar32*)wtext, len); - } else if (len==-1) { - wwarning(_("Conversion to widechar failed (possible invalid " - "multibyte sequence): '%s':(pos %d)\n"), - text, mtext-text+1); - /* we can draw normal text, or we can draw as much widechar - * text as was already converted until the error. go figure */ - /*XftDrawString8(scr->xftdraw, &textColor, font->font.xft, - x, y + font->y, (XftChar8*)text, length);*/ - } - wfree(wtext); - } else { - XftDrawString8(scr->xftdraw, &textColor, font->font.xft, - x, y + font->y, (XftChar8*)text, length); - } -#else - wassertr(False); -#endif - } else if (font->notFontSet) { - XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color)); - XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background)); - XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid); - XDrawImageString(scr->display, d, scr->drawImStringGC, - x, y + font->y, text, length); - } else { - XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color)); - XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background)); - XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC, - x, y + font->y, text, length); - } -} - - - - -static char* -makeFontSetOfSize(char *fontset, int size) -{ - char font[300], *f; - char *newfs = NULL; - char *ptr; - - do { - char *tmp; - int end; - - - f = fontset; - ptr = strchr(fontset, ','); - if (ptr) { - int count = ptr-fontset; - - if (count > 255) { - wwarning(_("font description %s is too large."), fontset); - } else { - memcpy(font, fontset, count); - font[count] = 0; - f = (char*)font; - } - } - - if (newfs) - end = strlen(newfs); - else - end = 0; - - tmp = wmalloc(end + strlen(f) + 8); - if (end != 0) { - sprintf(tmp, "%s,", newfs); - sprintf(tmp + end + 1, f, size); - } else { - sprintf(tmp + end, f, size); - } - - if (newfs) - wfree(newfs); - newfs = tmp; - - fontset = ptr+1; - } while (ptr!=NULL); - - return newfs; -} - - -#define FONT_PROPS 14 - -typedef struct { - char *props[FONT_PROPS]; -} W_FontAttributes; - - -static void -changeFontProp(char *buf, char *newprop, int position) -{ - char buf2[512]; - char *ptr, *pptr, *rptr; - int count; - - if (buf[0]!='-') { - /* // remove warning later. or maybe not */ - wwarning(_("Invalid font specification: '%s'\n"), buf); - return; - } - - ptr = pptr = rptr = buf; - count = 0; - while (*ptr && *ptr!=',') { - if (*ptr == '-') { - count++; - if (count-1==position+1) { - rptr = ptr; - break; - } - if (count-1==position) { - pptr = ptr+1; - } - } - ptr++; - } - if (position==FONT_PROPS-1) { - rptr = ptr; - } - - *pptr = 0; - snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr); - strcpy(buf, buf2); -} - - -static WMArray* -getOptions(char *options) -{ - char *ptr, *ptr2, *str; - WMArray *result; - int count; - - result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree); - - ptr = options; - while (1) { - ptr2 = strchr(ptr, ','); - if (!ptr2) { - WMAddToArray(result, wstrdup(ptr)); - break; - } else { - count = ptr2 - ptr; - str = wmalloc(count+1); - memcpy(str, ptr, count); - str[count] = 0; - WMAddToArray(result, str); - ptr = ptr2 + 1; - } - } - - return result; -} - - -#define WFAUnchanged (NULL) -/* Struct for font change operations */ -typedef struct WMFontAttributes { - char *foundry; - char *family; - char *weight; - char *slant; - char *setWidth; - char *addStyle; - char *pixelSize; - char *pointSize; - char *resolutionX; - char *resolutionY; - char *spacing; - char *averageWidth; - char *registry; - char *encoding; -} WMFontAttributes; - -WMFont* -WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font, - const WMFontAttributes *changes) -{ - int index[FONT_PROPS], count[FONT_PROPS]; - int totalProps, i, j, carry; - char fname[512]; - WMFontFlags fFlags; - WMBag *props; - WMArray *options; - WMFont *result; - char *prop; - - snprintf(fname, 512, "%s", font->name); - - fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased); - fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet); - - props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray); - - totalProps = 0; - for (i=0; iprops[i]; - count[i] = index[i] = 0; - if (!prop) { - /* No change for this property */ - continue; - } else if (strchr(prop, ',')==NULL) { - /* Simple option */ - changeFontProp(fname, prop, i); - } else { - /* Option with fallback alternatives */ - if ((changes==WFAEmphasized || changes==WFABoldEmphasized) && - font->antialiased && strcmp(prop, "o,i")==0) { - options = getOptions("i,o"); - } else { - options = getOptions(prop); - } - WMInsertInBag(props, i, options); - count[i] = WMGetArrayItemCount(options); - if (totalProps==0) - totalProps = 1; - totalProps = totalProps * count[i]; - } - } - - if (totalProps == 0) { - /* No options with fallback alternatives at all */ - WMFreeBag(props); - return WMCreateFontWithFlags(scrPtr, fname, fFlags); - } - - for (i=0; i=0; j--) { - if (count[j]!=0) { - index[j] += carry; - carry = (index[j]==count[j]); - index[j] %= count[j]; - } - } - } - - WMFreeBag(props); - - return NULL; -} - -// should WFANormal also set "normal" or leave it alone? -static const WMFontAttributes W_FANormal = { - WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal", - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -static const WMFontAttributes W_FABold = { - WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -static const WMFontAttributes W_FANotBold = { - WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -static const WMFontAttributes W_FAEmphasized = { - WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i", - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -static const WMFontAttributes W_FANotEmphasized = { - WFAUnchanged, WFAUnchanged, WFAUnchanged, "r", - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -static const WMFontAttributes W_FABoldEmphasized = { - WFAUnchanged, WFAUnchanged, "bold", "o,i", - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, - WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged -}; - - -const WMFontAttributes *WFANormal = &W_FANormal; -const WMFontAttributes *WFABold = &W_FABold; -const WMFontAttributes *WFANotBold = &W_FANotBold; -const WMFontAttributes *WFAEmphasized = &W_FAEmphasized; -const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized; -const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized; - - -#endif - - + +#include "wconfig.h" + +#ifdef XFT + +#include +#include + +#include + +#include "WINGsP.h" + +#include +#include +#include + + +#define DEFAULT_SIZE WINGsConfiguration.defaultFontSize + +static char* +fixXLFD(char *xlfd, int size) +{ + char *fname, *ptr; + + fname = wmalloc(strlen(xlfd) + 20); + if (strstr(xlfd, "%d")!=NULL) + sprintf(fname, xlfd, size ? size : DEFAULT_SIZE); + else + strcpy(fname, xlfd); + + if ((ptr = strchr(fname, ','))) { + *ptr = 0; + } + + return fname; +} + + +static Bool +hasProperty(FcPattern *pattern, const char *property) +{ + FcValue val; + + if (FcPatternGet(pattern, property, 0, &val)==FcResultMatch) { + return True; + } + + return False; +} + + +static Bool +hasPropertyWithStringValue(FcPattern *pattern, const char *object, char *value) +{ + FcChar8 *str; + int id; + + if (!value || value[0]==0) + return True; + + id = 0; + while (FcPatternGetString(pattern, object, id, &str)==FcResultMatch) { + if (strcasecmp(value, (char*)str) == 0) { + return True; + } + id++; + } + + return False; +} + + +// also handle an xlfd with %d for size? +static char* +makeFontOfSize(char *font, int size, char *fallback) +{ + FcPattern *pattern; + char *result; + + if (font[0]=='-') { + char *fname; + + fname = fixXLFD(font, size); + pattern = XftXlfdParse(fname, False, False); + wfree(fname); + } else { + pattern = FcNameParse(font); + } + + //FcPatternPrint(pattern); + if (size > 0) { + FcPatternDel(pattern, "pixelsize"); + FcPatternAddDouble(pattern, "pixelsize", (double)size); + } else if (size==0 && !hasProperty(pattern, "size") && + !hasProperty(pattern, "pixelsize")) { + FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE); + } + + if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) { + FcPatternAddString(pattern, "family", fallback); + } + + result = FcNameUnparse(pattern); + FcPatternDestroy(pattern); + + return result; +} + + +WMFont* +WMCreateFont(WMScreen *scrPtr, char *fontName) +{ + WMFont *font; + Display *display = scrPtr->display; + char *fname, *ptr; + + /* This is for back-compat (to allow reading of old xlfd descriptions) */ + if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) { + // warn for deprecation + fname = wmalloc(ptr - fontName + 1); + strncpy(fname, fontName, ptr - fontName); + fname[ptr - fontName] = 0; + } else { + fname = wstrdup(fontName); + } + + font = WMHashGet(scrPtr->fontCache, fname); + if (font) { + WMRetainFont(font); + wfree(fname); + return font; + } + + font = wmalloc(sizeof(WMFont)); + memset(font, 0, sizeof(WMFont)); + + font->screen = scrPtr; + + // remove + printf("WMCreateFont: %s\n", fname); + + if (fname[0] == '-') { + // Backward compat thing. Remove in a later version + font->font = XftFontOpenXlfd(display, scrPtr->screen, fname); + } else { + font->font = XftFontOpenName(display, scrPtr->screen, fname); + } + if (!font->font) { + wfree(font); + wfree(fname); + return NULL; + } + font->height = font->font->ascent+font->font->descent; + font->y = font->font->ascent; + + font->refCount = 1; + + font->name = fname; + + assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL); + + return font; +} + + +WMFont* +WMRetainFont(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + font->refCount++; + + return font; +} + + +void +WMReleaseFont(WMFont *font) +{ + wassertr(font!=NULL); + + font->refCount--; + if (font->refCount < 1) { + XftFontClose(font->screen->display, font->font); + if (font->name) { + WMHashRemove(font->screen->fontCache, font->name); + wfree(font->name); + } + wfree(font); + } +} + + +Bool +WMIsAntialiasingEnabled(WMScreen *scrPtr) +{ + return scrPtr->antialiasedText; +} + + +unsigned int +WMFontHeight(WMFont *font) +{ + wassertrv(font!=NULL, 0); + + return font->height; +} + + +char* +WMGetFontName(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + return font->name; +} + + +WMFont* +WMDefaultSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->normalFont); +} + + +WMFont* +WMDefaultBoldSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->boldFont); +} + + +WMFont* +WMSystemFontOfSize(WMScreen *scrPtr, int size) +{ + WMFont *font; + char *fontSpec; + + fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans"); + + font = WMCreateFont(scrPtr, fontSpec); + + if (!font) { + wwarning(_("could not load font %s."), fontSpec); + } + + wfree(fontSpec); + + return font; +} + + +WMFont* +WMBoldSystemFontOfSize(WMScreen *scrPtr, int size) +{ + WMFont *font; + char *fontSpec; + + fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans"); + + font = WMCreateFont(scrPtr, fontSpec); + + if (!font) { + wwarning(_("could not load font %s."), fontSpec); + } + + wfree(fontSpec); + + return font; +} + + +int +WMWidthOfString(WMFont *font, char *text, int length) +{ + XGlyphInfo extents; + + wassertrv(font!=NULL && text!=NULL, 0); + + XftTextExtentsUtf8(font->screen->display, font->font, + (XftChar8 *)text, length, &extents); + + return extents.xOff; /* don't ask :P */ +} + + + +void +WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, + int x, int y, char *text, int length) +{ + XftColor xftcolor; + + wassertr(font!=NULL); + + xftcolor.color.red = color->color.red; + xftcolor.color.green = color->color.green; + xftcolor.color.blue = color->color.blue; + xftcolor.color.alpha = color->alpha;; + xftcolor.pixel = W_PIXEL(color); + + XftDrawChange(scr->xftdraw, d); + + XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, + x, y + font->y, (XftChar8*)text, length); +} + + +void +WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background, + WMFont *font, int x, int y, char *text, int length) +{ + XftColor textColor; + XftColor bgColor; + + wassertr(font!=NULL); + + textColor.color.red = color->color.red; + textColor.color.green = color->color.green; + textColor.color.blue = color->color.blue; + textColor.color.alpha = color->alpha;; + textColor.pixel = W_PIXEL(color); + + bgColor.color.red = background->color.red; + bgColor.color.green = background->color.green; + bgColor.color.blue = background->color.blue; + bgColor.color.alpha = background->alpha;; + bgColor.pixel = W_PIXEL(background); + + XftDrawChange(scr->xftdraw, d); + + XftDrawRect(scr->xftdraw, &bgColor, x, y, + WMWidthOfString(font, text, length), + font->height); + + XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, + x, y + font->y, (XftChar8*)text, length); +} + + +WMFont* +WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style) +{ + FcPattern *pattern; + WMFont *copy; + char *name; + + if (!font) + return NULL; + + pattern = FcNameParse(WMGetFontName(font)); + switch (style) { + case WFSNormal: + FcPatternDel(pattern, "weight"); + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "weight", "regular"); + FcPatternAddString(pattern, "weight", "medium"); + FcPatternAddString(pattern, "slant", "roman"); + break; + case WFSBold: + FcPatternDel(pattern, "weight"); + FcPatternAddString(pattern, "weight", "bold"); + break; + case WFSEmphasized: + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "slant", "italic"); + FcPatternAddString(pattern, "slant", "oblique"); + break; + case WFSBoldEmphasized: + FcPatternDel(pattern, "weight"); + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "weight", "bold"); + FcPatternAddString(pattern, "slant", "italic"); + FcPatternAddString(pattern, "slant", "oblique"); + break; + } + + name = FcNameUnparse(pattern); + copy = WMCreateFont(scrPtr, name); + FcPatternDestroy(pattern); + wfree(name); + + return copy; +} + + +#endif /* XFT */ + + diff --git a/WINGs/wfont_noxft.c b/WINGs/wfont_noxft.c new file mode 100644 index 00000000..ffd817c7 --- /dev/null +++ b/WINGs/wfont_noxft.c @@ -0,0 +1,769 @@ + + +#include "wconfig.h" + +#ifndef XFT + +#include "WINGsP.h" + +#include +#include +#include + + +static char *makeFontSetOfSize(char *fontset, int size); + + +/* XLFD pattern matching */ +static char* +getElementFromXLFD(const char *xlfd, int index) +{ + const char *p = xlfd; + while (*p != 0) { + if (*p == '-' && --index == 0) { + const char *end = strchr(p + 1, '-'); + char *buf; + size_t len; + if (end == 0) end = p + strlen(p); + len = end - (p + 1); + buf = wmalloc(len); + memcpy(buf, p + 1, len); + buf[len] = 0; + return buf; + } + p++; + } + return strdup("*"); +} + + +/* XLFD pattern matching */ +static char* +generalizeXLFD(const char *xlfd) +{ + char *buf; + int len; + char *weight = getElementFromXLFD(xlfd, 3); + char *slant = getElementFromXLFD(xlfd, 4); + char *pxlsz = getElementFromXLFD(xlfd, 7); + +#define Xstrlen(A) ((A)?strlen(A):0) + len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+60; +#undef Xstrlen + + buf = wmalloc(len + 1); + snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*," + "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*", + xlfd, weight, slant, pxlsz, pxlsz); + + wfree(pxlsz); + wfree(slant); + wfree(weight); + + return buf; +} + +/* XLFD pattern matching */ +static XFontSet +W_CreateFontSetWithGuess(Display *dpy, char *xlfd, char ***missing, + int *nmissing, char **def_string) +{ + XFontSet fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); + + if (fs != NULL && *nmissing == 0) return fs; + + /* for non-iso8859-1 language and iso8859-1 specification + (this fontset is only for pattern analysis) */ + if (fs == NULL) { + if (*nmissing != 0) XFreeStringList(*missing); + setlocale(LC_CTYPE, "C"); + fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); + setlocale(LC_CTYPE, ""); + } + + /* make XLFD font name for pattern analysis */ + if (fs != NULL) { + XFontStruct **fontstructs; + char **fontnames; + if (XFontsOfFontSet(fs, &fontstructs, &fontnames) > 0) + xlfd = fontnames[0]; + } + + xlfd = generalizeXLFD(xlfd); + + if (*nmissing != 0) XFreeStringList(*missing); + if (fs != NULL) XFreeFontSet(dpy, fs); + + fs = XCreateFontSet(dpy, xlfd, missing, nmissing, def_string); + + wfree(xlfd); + return fs; +} + + +static char* +xlfdFromFontName(char *fontName) +{ + char *systemFont, *boldSystemFont; + char *font; + int size; + + systemFont = WINGsConfiguration.systemFont; + boldSystemFont = WINGsConfiguration.boldSystemFont; + + size = WINGsConfiguration.defaultFontSize; + + if (strcmp(fontName, "SystemFont")==0) { + font = systemFont; + } else if (strncmp(fontName, "SystemFont-", 11)==0) { + font = systemFont; + if (sscanf(&fontName[11], "%i", &size)!=1) { + size = WINGsConfiguration.defaultFontSize; + wwarning(_("Invalid size specification '%s' in %s. " + "Using default %d\n"), &fontName[11], fontName, size); + } + } else if (strcmp(fontName, "BoldSystemFont")==0) { + font = boldSystemFont; + } else if (strncmp(fontName, "BoldSystemFont-", 15)==0) { + font = boldSystemFont; + if (sscanf(&fontName[15], "%i", &size)!=1) { + size = WINGsConfiguration.defaultFontSize; + wwarning(_("Invalid size specification '%s' in %s. " + "Using default %d\n"), &fontName[15], fontName, size); + } + } else { + font = NULL; + } + + return (font!=NULL ? makeFontSetOfSize(font, size) : wstrdup(fontName)); +} + + +WMFont* +WMCreateFontSet(WMScreen *scrPtr, char *fontName) +{ + WMFont *font; + Display *display = scrPtr->display; + char **missing; + int nmissing = 0; + char *defaultString; + char *fname; + XFontSetExtents *extents; + + fname = xlfdFromFontName(fontName); + + font = WMHashGet(scrPtr->fontSetCache, fname); + if (font) { + WMRetainFont(font); + wfree(fname); + return font; + } + + font = wmalloc(sizeof(WMFont)); + memset(font, 0, sizeof(WMFont)); + + font->notFontSet = 0; + + font->screen = scrPtr; + + font->font.set = W_CreateFontSetWithGuess(display, fname, &missing, + &nmissing, &defaultString); + if (nmissing > 0 && font->font.set) { + int i; + + wwarning(_("the following character sets are missing in %s:"), fname); + for (i = 0; i < nmissing; i++) { + wwarning(missing[i]); + } + XFreeStringList(missing); + if (defaultString) + wwarning(_("the string \"%s\" will be used in place of any characters from those sets."), + defaultString); + } + if (!font->font.set) { + wfree(font); + wfree(fname); + return NULL; + } + + extents = XExtentsOfFontSet(font->font.set); + + font->height = extents->max_logical_extent.height; + font->y = font->height - (font->height + extents->max_logical_extent.y); + + font->refCount = 1; + + font->name = fname; + + assert(WMHashInsert(scrPtr->fontSetCache, font->name, font)==NULL); + + return font; +} + + + +WMFont* +WMCreateNormalFont(WMScreen *scrPtr, char *fontName) +{ + WMFont *font; + Display *display = scrPtr->display; + char *fname, *ptr; + + fontName = xlfdFromFontName(fontName); + + if ((ptr = strchr(fontName, ','))) { + fname = wmalloc(ptr - fontName + 1); + strncpy(fname, fontName, ptr - fontName); + fname[ptr - fontName] = 0; + } else { + fname = wstrdup(fontName); + } + + wfree(fontName); + + font = WMHashGet(scrPtr->fontCache, fname); + if (font) { + WMRetainFont(font); + wfree(fname); + return font; + } + + font = wmalloc(sizeof(WMFont)); + memset(font, 0, sizeof(WMFont)); + + font->notFontSet = 1; + + font->screen = scrPtr; + + font->font.normal = XLoadQueryFont(display, fname); + if (!font->font.normal) { + wfree(font); + wfree(fname); + return NULL; + } + font->height = font->font.normal->ascent+font->font.normal->descent; + font->y = font->font.normal->ascent; + + font->refCount = 1; + + font->name = fname; + + assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL); + + return font; +} + + +WMFont* +WMCreateFont(WMScreen *scrPtr, char *fontName) +{ + return WMCreateFontWithFlags(scrPtr, fontName, WFDefaultFont); +} + + +WMFont* +WMCreateFontWithFlags(WMScreen *scrPtr, char *fontName, WMFontFlags flags) +{ + Bool multiByte = scrPtr->useMultiByte; + WMFont *font; + + if (flags & WFFontSet) { + multiByte = True; + } else if (flags & WFNormalFont) { + multiByte = False; + } + + } else if (multiByte) { + font = WMCreateFontSet(scrPtr, fontName); + } else { + font = WMCreateNormalFont(scrPtr, fontName); + } + + return font; +} + + +WMFont* +WMRetainFont(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + font->refCount++; + + return font; +} + + +void +WMReleaseFont(WMFont *font) +{ + wassertr(font!=NULL); + + font->refCount--; + if (font->refCount < 1) { + if (font->notFontSet) { + XFreeFont(font->screen->display, font->font.normal); + } else { + XFreeFontSet(font->screen->display, font->font.set); + } + + if (font->name) { + if (font->notFontSet) { + WMHashRemove(font->screen->fontCache, font->name); + } else { + WMHashRemove(font->screen->fontSetCache, font->name); + } + wfree(font->name); + } + wfree(font); + } +} + + +Bool +WMIsAntialiasingEnabled(WMScreen *scrPtr) +{ + return False; +} + + +unsigned int +WMFontHeight(WMFont *font) +{ + wassertrv(font!=NULL, 0); + + return font->height; +} + + +char* +WMGetFontName(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + return font->name; +} + + +WMFont* +WMDefaultSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->normalFont); +} + + +WMFont* +WMDefaultBoldSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->boldFont); +} + + +static WMFont* +makeSystemFontOfSize(WMScreen *scrPtr, int size, Bool bold) +{ + WMFont *font; + char *fontSpec; + +#define WConf WINGsConfiguration + if (bold) { + fontSpec = makeFontSetOfSize(WConf.boldSystemFont, size); + } else { + fontSpec = makeFontSetOfSize(WConf.systemFont, size); + } +#undef WConf + + if (scrPtr->useMultiByte) { + font = WMCreateFontSet(scrPtr, fontSpec); + } else { + font = WMCreateNormalFont(scrPtr, fontSpec); + } + + if (!font) { + if (scrPtr->useMultiByte) { + wwarning(_("could not load font set %s. Trying fixed."), fontSpec); + font = WMCreateFontSet(scrPtr, "fixed"); + if (!font) { + font = WMCreateFontSet(scrPtr, "-*-fixed-medium-r-normal-*-14-*-*-*-*-*-*-*"); + } + } else { + wwarning(_("could not load font %s. Trying fixed."), fontSpec); + font = WMCreateNormalFont(scrPtr, "fixed"); + } + if (!font) { + wwarning(_("could not load fixed font!")); + wfree(fontSpec); + return NULL; + } + } + wfree(fontSpec); + + return font; +} + + +WMFont* +WMSystemFontOfSize(WMScreen *scrPtr, int size) +{ + return makeSystemFontOfSize(scrPtr, size, False); +} + + +WMFont* +WMBoldSystemFontOfSize(WMScreen *scrPtr, int size) +{ + return makeSystemFontOfSize(scrPtr, size, True); +} + + +XFontSet +WMGetFontFontSet(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + if (!font->notFontSet && !font->antialiased) + return font->font.set; + + return NULL; +} + + +int +WMWidthOfString(WMFont *font, char *text, int length) +{ + wassertrv(font!=NULL, 0); + wassertrv(text!=NULL, 0); + + if (font->notFontSet) { + return XTextWidth(font->font.normal, text, length); + } else { + XRectangle rect; + XRectangle AIXsucks; + + XmbTextExtents(font->font.set, text, length, &AIXsucks, &rect); + + return rect.width; + } +} + + + +void +WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, + int x, int y, char *text, int length) +{ + wassertr(font!=NULL); + + if (font->notFontSet) { + XSetFont(scr->display, scr->drawStringGC, font->font.normal->fid); + XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color)); + XDrawString(scr->display, d, scr->drawStringGC, x, y + font->y, + text, length); + } else { + XSetForeground(scr->display, scr->drawStringGC, W_PIXEL(color)); + XmbDrawString(scr->display, d, font->font.set, scr->drawStringGC, + x, y + font->y, text, length); + } +} + + +void +WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background, + WMFont *font, int x, int y, char *text, int length) +{ + wassertr(font!=NULL); + + if (font->notFontSet) { + XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color)); + XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background)); + XSetFont(scr->display, scr->drawImStringGC, font->font.normal->fid); + XDrawImageString(scr->display, d, scr->drawImStringGC, + x, y + font->y, text, length); + } else { + XSetForeground(scr->display, scr->drawImStringGC, W_PIXEL(color)); + XSetBackground(scr->display, scr->drawImStringGC, W_PIXEL(background)); + XmbDrawImageString(scr->display, d, font->font.set, scr->drawImStringGC, + x, y + font->y, text, length); + } +} + + + + +static char* +makeFontSetOfSize(char *fontset, int size) +{ + char font[300], *f; + char *newfs = NULL; + char *ptr; + + do { + char *tmp; + int end; + + + f = fontset; + ptr = strchr(fontset, ','); + if (ptr) { + int count = ptr-fontset; + + if (count > 255) { + wwarning(_("font description %s is too large."), fontset); + } else { + memcpy(font, fontset, count); + font[count] = 0; + f = (char*)font; + } + } + + if (newfs) + end = strlen(newfs); + else + end = 0; + + tmp = wmalloc(end + strlen(f) + 8); + if (end != 0) { + sprintf(tmp, "%s,", newfs); + sprintf(tmp + end + 1, f, size); + } else { + sprintf(tmp + end, f, size); + } + + if (newfs) + wfree(newfs); + newfs = tmp; + + fontset = ptr+1; + } while (ptr!=NULL); + + return newfs; +} + + +#define FONT_PROPS 14 + +typedef struct { + char *props[FONT_PROPS]; +} W_FontAttributes; + + +static void +changeFontProp(char *buf, char *newprop, int position) +{ + char buf2[512]; + char *ptr, *pptr, *rptr; + int count; + + if (buf[0]!='-') { + /* // remove warning later. or maybe not */ + wwarning(_("Invalid font specification: '%s'\n"), buf); + return; + } + + ptr = pptr = rptr = buf; + count = 0; + while (*ptr && *ptr!=',') { + if (*ptr == '-') { + count++; + if (count-1==position+1) { + rptr = ptr; + break; + } + if (count-1==position) { + pptr = ptr+1; + } + } + ptr++; + } + if (position==FONT_PROPS-1) { + rptr = ptr; + } + + *pptr = 0; + snprintf(buf2, 512, "%s%s%s", buf, newprop, rptr); + strcpy(buf, buf2); +} + + +static WMArray* +getOptions(char *options) +{ + char *ptr, *ptr2, *str; + WMArray *result; + int count; + + result = WMCreateArrayWithDestructor(2, (WMFreeDataProc*)wfree); + + ptr = options; + while (1) { + ptr2 = strchr(ptr, ','); + if (!ptr2) { + WMAddToArray(result, wstrdup(ptr)); + break; + } else { + count = ptr2 - ptr; + str = wmalloc(count+1); + memcpy(str, ptr, count); + str[count] = 0; + WMAddToArray(result, str); + ptr = ptr2 + 1; + } + } + + return result; +} + + +#define WFAUnchanged (NULL) +/* Struct for font change operations */ +typedef struct WMFontAttributes { + char *foundry; + char *family; + char *weight; + char *slant; + char *setWidth; + char *addStyle; + char *pixelSize; + char *pointSize; + char *resolutionX; + char *resolutionY; + char *spacing; + char *averageWidth; + char *registry; + char *encoding; +} WMFontAttributes; + +WMFont* +WMCopyFontWithChanges(WMScreen *scrPtr, WMFont *font, + const WMFontAttributes *changes) +{ + int index[FONT_PROPS], count[FONT_PROPS]; + int totalProps, i, j, carry; + char fname[512]; + WMFontFlags fFlags; + WMBag *props; + WMArray *options; + WMFont *result; + char *prop; + + snprintf(fname, 512, "%s", font->name); + + fFlags = (font->antialiased ? WFAntialiased : WFNotAntialiased); + fFlags |= (font->notFontSet ? WFNormalFont : WFFontSet); + + props = WMCreateBagWithDestructor(1, (WMFreeDataProc*)WMFreeArray); + + totalProps = 0; + for (i=0; iprops[i]; + count[i] = index[i] = 0; + if (!prop) { + /* No change for this property */ + continue; + } else if (strchr(prop, ',')==NULL) { + /* Simple option */ + changeFontProp(fname, prop, i); + } else { + /* Option with fallback alternatives */ + if ((changes==WFAEmphasized || changes==WFABoldEmphasized) && + font->antialiased && strcmp(prop, "o,i")==0) { + options = getOptions("i,o"); + } else { + options = getOptions(prop); + } + WMInsertInBag(props, i, options); + count[i] = WMGetArrayItemCount(options); + if (totalProps==0) + totalProps = 1; + totalProps = totalProps * count[i]; + } + } + + if (totalProps == 0) { + /* No options with fallback alternatives at all */ + WMFreeBag(props); + return WMCreateFontWithFlags(scrPtr, fname, fFlags); + } + + for (i=0; i=0; j--) { + if (count[j]!=0) { + index[j] += carry; + carry = (index[j]==count[j]); + index[j] %= count[j]; + } + } + } + + WMFreeBag(props); + + return NULL; +} + +// should WFANormal also set "normal" or leave it alone? +static const WMFontAttributes W_FANormal = { + WFAUnchanged, WFAUnchanged, "medium,normal,regular", "r", "normal", + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +static const WMFontAttributes W_FABold = { + WFAUnchanged, WFAUnchanged, "bold", WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +static const WMFontAttributes W_FANotBold = { + WFAUnchanged, WFAUnchanged, "medium,normal,regular", WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +static const WMFontAttributes W_FAEmphasized = { + WFAUnchanged, WFAUnchanged, WFAUnchanged, "o,i", + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +static const WMFontAttributes W_FANotEmphasized = { + WFAUnchanged, WFAUnchanged, WFAUnchanged, "r", + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +static const WMFontAttributes W_FABoldEmphasized = { + WFAUnchanged, WFAUnchanged, "bold", "o,i", + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, + WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged, WFAUnchanged +}; + + +const WMFontAttributes *WFANormal = &W_FANormal; +const WMFontAttributes *WFABold = &W_FABold; +const WMFontAttributes *WFANotBold = &W_FANotBold; +const WMFontAttributes *WFAEmphasized = &W_FAEmphasized; +const WMFontAttributes *WFANotEmphasized = &W_FANotEmphasized; +const WMFontAttributes *WFABoldEmphasized = &W_FABoldEmphasized; + + +#endif + diff --git a/WINGs/wfont_wchar.c b/WINGs/wfont_wchar.c new file mode 100644 index 00000000..cfc6f03c --- /dev/null +++ b/WINGs/wfont_wchar.c @@ -0,0 +1,599 @@ + +#include "wconfig.h" + +#ifdef XFT + +#include +#include + +#if defined(HAVE_MBSNRTOWCS) +# define __USE_GNU +#endif + +#ifdef HAVE_WCHAR_H +# include +#endif + +#include + +#include "WINGsP.h" + +#include +#include +#include + + +// && defined(HAVE_MBSTATE_T___COUNT) +// in configure.ac use AC_CHECK_MEMBER(struct mbstate_t.__count, +// have=1, have=0, [#include ]) +#if defined(HAVE_MBSNRTOWCS) + +static size_t +wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) +{ + mbstate_t ps; + size_t n; + + memset(&ps, 0, sizeof(mbstate_t)); + n = mbsnrtowcs(dest, src, nbytes, len, &ps); + if (n!=(size_t)-1 && *src) { + *src -= ps.__count; + } + + return n; +} + +#elif defined(HAVE_MBRTOWC) + +// This is 8 times slower than the version above. +static size_t +wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) +{ + mbstate_t ps; + const char *ptr; + size_t n; + int nb; + + if (nbytes==0) + return 0; + + memset(&ps, 0, sizeof(mbstate_t)); + + if (dest == NULL) { + for (ptr=*src, n=0; nbytes>0; n++) { + nb = mbrtowc(NULL, ptr, nbytes, &ps); + if (nb == -1) { + return ((size_t)-1); + } else if (nb==0 || nb==-2) { + return n; + } + ptr += nb; + nbytes -= nb; + } + } + + for (ptr=*src, n=0; n0; n++, dest++) { + nb = mbrtowc(dest, ptr, nbytes, &ps); + if (nb == -2) { + *src = ptr; + return n; + } else if (nb == -1) { + *src = ptr; + return ((size_t)-1); + } else if (nb == 0) { + *src = NULL; + return n; + } + ptr += nb; + nbytes -= nb; + } + + *src = ptr; + return n; +} + +#else + +// Not only 8 times slower than the version based on mbsnrtowcs +// but also this version is not thread safe nor reentrant + +static size_t +wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) +{ + const char *ptr; + size_t n; + int nb; + + if (nbytes==0) + return 0; + + mbtowc(NULL, NULL, 0); /* reset shift state */ + + if (dest == NULL) { + for (ptr=*src, n=0; nbytes>0; n++) { + nb = mbtowc(NULL, ptr, nbytes); + if (nb == -1) { + mbtowc(NULL, NULL, 0); + nb = mbtowc(NULL, ptr, strlen(ptr)); + return (nb == -1 ? (size_t)-1 : n); + } else if (nb==0) { + return n; + } + ptr += nb; + nbytes -= nb; + } + } + + for (ptr=*src, n=0; n0; n++, dest++) { + nb = mbtowc(dest, ptr, nbytes); + if (nb == -1) { + mbtowc(NULL, NULL, 0); + nb = mbtowc(NULL, ptr, strlen(ptr)); + *src = ptr; + return (nb == -1 ? (size_t)-1 : n); + } else if (nb == 0) { + *src = NULL; + return n; + } + ptr += nb; + nbytes -= nb; + } + + *src = ptr; + return n; +} + +#endif + + +#define DEFAULT_SIZE 12 + +static char* +fixXLFD(char *xlfd, int size) +{ + char *fname, *ptr; + + fname = wmalloc(strlen(xlfd) + 20); + if (strstr(xlfd, "%d")!=NULL) + sprintf(fname, xlfd, size ? size : DEFAULT_SIZE); + else + strcpy(fname, xlfd); + + if ((ptr = strchr(fname, ','))) { + *ptr = 0; + } + + return fname; +} + + +static Bool +hasProperty(FcPattern *pattern, const char *property) +{ + FcValue val; + + if (FcPatternGet(pattern, property, 0, &val)==FcResultMatch) { + return True; + } + + return False; +} + + +static Bool +hasPropertyWithStringValue(FcPattern *pattern, const char *object, char *value) +{ + FcChar8 *str; + int id; + + if (!value || value[0]==0) + return True; + + id = 0; + while (FcPatternGetString(pattern, object, id, &str)==FcResultMatch) { + if (strcasecmp(value, (char*)str) == 0) { + return True; + } + id++; + } + + return False; +} + + +// also handle an xlfd with %d for size? +static char* +makeFontOfSize(char *font, int size, char *fallback) +{ + FcPattern *pattern; + char *result; + + if (font[0]=='-') { + char *fname; + + fname = fixXLFD(font, size); + pattern = XftXlfdParse(fname, False, False); + wfree(fname); + } else { + pattern = FcNameParse(font); + } + + //FcPatternPrint(pattern); + if (size > 0) { + FcPatternDel(pattern, "pixelsize"); + FcPatternAddDouble(pattern, "pixelsize", (double)size); + } else if (size==0 && !hasProperty(pattern, "size") && + !hasProperty(pattern, "pixelsize")) { + FcPatternAddDouble(pattern, "pixelsize", (double)DEFAULT_SIZE); + } + + if (fallback && !hasPropertyWithStringValue(pattern, "family", fallback)) { + FcPatternAddString(pattern, "family", fallback); + } + + result = FcNameUnparse(pattern); + FcPatternDestroy(pattern); + + return result; +} + + +WMFont* +WMCreateFont(WMScreen *scrPtr, char *fontName) +{ + WMFont *font; + Display *display = scrPtr->display; + char *fname, *ptr; + + /* This is for back-compat (to allow reading of old xlfd descriptions) */ + if (fontName[0]=='-' && (ptr = strchr(fontName, ','))) { + // warn for deprecation + fname = wmalloc(ptr - fontName + 1); + strncpy(fname, fontName, ptr - fontName); + fname[ptr - fontName] = 0; + } else { + fname = wstrdup(fontName); + } + + font = WMHashGet(scrPtr->fontCache, fname); + if (font) { + WMRetainFont(font); + wfree(fname); + return font; + } + + font = wmalloc(sizeof(WMFont)); + memset(font, 0, sizeof(WMFont)); + + font->screen = scrPtr; + + // remove + printf("WMCreateFont: %s\n", fname); + + if (fname[0] == '-') { + // Backward compat thing. Remove in a later version + font->font = XftFontOpenXlfd(display, scrPtr->screen, fname); + } else { + font->font = XftFontOpenName(display, scrPtr->screen, fname); + } + if (!font->font) { + wfree(font); + wfree(fname); + return NULL; + } + font->height = font->font->ascent+font->font->descent; + font->y = font->font->ascent; + + font->refCount = 1; + + font->name = fname; + + assert(WMHashInsert(scrPtr->fontCache, font->name, font)==NULL); + + return font; +} + + +WMFont* +WMRetainFont(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + font->refCount++; + + return font; +} + + +void +WMReleaseFont(WMFont *font) +{ + wassertr(font!=NULL); + + font->refCount--; + if (font->refCount < 1) { + XftFontClose(font->screen->display, font->font); + if (font->name) { + WMHashRemove(font->screen->fontCache, font->name); + wfree(font->name); + } + wfree(font); + } +} + + +Bool +WMIsAntialiasingEnabled(WMScreen *scrPtr) +{ + return scrPtr->antialiasedText; +} + + +unsigned int +WMFontHeight(WMFont *font) +{ + wassertrv(font!=NULL, 0); + + return font->height; +} + + +char* +WMGetFontName(WMFont *font) +{ + wassertrv(font!=NULL, NULL); + + return font->name; +} + + +WMFont* +WMDefaultSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->normalFont); +} + + +WMFont* +WMDefaultBoldSystemFont(WMScreen *scrPtr) +{ + return WMRetainFont(scrPtr->boldFont); +} + + +WMFont* +WMSystemFontOfSize(WMScreen *scrPtr, int size) +{ + WMFont *font; + char *fontSpec; + + fontSpec = makeFontOfSize(WINGsConfiguration.systemFont, size, "sans"); + + font = WMCreateFont(scrPtr, fontSpec); + + if (!font) { + wwarning(_("could not load font %s."), fontSpec); + } + + wfree(fontSpec); + + return font; +} + + +WMFont* +WMBoldSystemFontOfSize(WMScreen *scrPtr, int size) +{ + WMFont *font; + char *fontSpec; + + fontSpec = makeFontOfSize(WINGsConfiguration.boldSystemFont, size, "sans"); + + font = WMCreateFont(scrPtr, fontSpec); + + if (!font) { + wwarning(_("could not load font %s."), fontSpec); + } + + wfree(fontSpec); + + return font; +} + + +int +WMWidthOfString(WMFont *font, char *text, int length) +{ + XGlyphInfo extents; + + wassertrv(font!=NULL, 0); + wassertrv(text!=NULL, 0); + + if (font->screen->useWideChar) { + wchar_t *wtext; + const char *mtext; + int len; + + wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); + mtext = text; + len = wmbsnrtowcs(wtext, &mtext, length, length); + if (len>0) { + wtext[len] = L'\0'; /* not really necessary here */ + XftTextExtents32(font->screen->display, font->font, + (XftChar32 *)wtext, len, &extents); + } else { + if (len==-1) { + wwarning(_("Conversion to widechar failed (possible " + "invalid multibyte sequence): '%s':(pos %d)\n"), + text, mtext-text+1); + } + extents.xOff = 0; + } + wfree(wtext); + } else if (font->screen->useMultiByte) { + XftTextExtentsUtf8(font->screen->display, font->font, + (XftChar8 *)text, length, &extents); + } else { + XftTextExtents8(font->screen->display, font->font, + (XftChar8 *)text, length, &extents); + } + + return extents.xOff; /* don't ask :P */ +} + + + +void +WMDrawString(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, + int x, int y, char *text, int length) +{ + XftColor xftcolor; + + wassertr(font!=NULL); + + xftcolor.color.red = color->color.red; + xftcolor.color.green = color->color.green; + xftcolor.color.blue = color->color.blue; + xftcolor.color.alpha = color->alpha;; + xftcolor.pixel = W_PIXEL(color); + + XftDrawChange(scr->xftdraw, d); + + if (font->screen->useWideChar) { + wchar_t *wtext; + const char *mtext; + int len; + + wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); + mtext = text; + len = wmbsnrtowcs(wtext, &mtext, length, length); + if (len>0) { + XftDrawString32(scr->xftdraw, &xftcolor, font->font, + x, y + font->y, (XftChar32*)wtext, len); + } else if (len==-1) { + wwarning(_("Conversion to widechar failed (possible invalid " + "multibyte sequence): '%s':(pos %d)\n"), + text, mtext-text+1); + /* we can draw normal text, or we can draw as much widechar + * text as was already converted until the error. go figure */ + /*XftDrawString8(scr->xftdraw, &xftcolor, font->font, + x, y + font->y, (XftChar8*)text, length);*/ + } + wfree(wtext); + } else if (font->screen->useMultiByte) { + XftDrawStringUtf8(scr->xftdraw, &xftcolor, font->font, + x, y + font->y, (XftChar8*)text, length); + } else { + XftDrawString8(scr->xftdraw, &xftcolor, font->font, + x, y + font->y, (XftChar8*)text, length); + } +} + + +void +WMDrawImageString(WMScreen *scr, Drawable d, WMColor *color, WMColor *background, + WMFont *font, int x, int y, char *text, int length) +{ + XftColor textColor; + XftColor bgColor; + + wassertr(font!=NULL); + + textColor.color.red = color->color.red; + textColor.color.green = color->color.green; + textColor.color.blue = color->color.blue; + textColor.color.alpha = color->alpha;; + textColor.pixel = W_PIXEL(color); + + bgColor.color.red = background->color.red; + bgColor.color.green = background->color.green; + bgColor.color.blue = background->color.blue; + bgColor.color.alpha = background->alpha;; + bgColor.pixel = W_PIXEL(background); + + XftDrawChange(scr->xftdraw, d); + + XftDrawRect(scr->xftdraw, &bgColor, x, y, + WMWidthOfString(font, text, length), + font->height); + + if (font->screen->useWideChar) { + wchar_t *wtext; + const char *mtext; + int len; + + mtext = text; + wtext = (wchar_t *)wmalloc(sizeof(wchar_t)*(length+1)); + len = wmbsnrtowcs(wtext, &mtext, length, length); + if (len>0) { + XftDrawString32(scr->xftdraw, &textColor, font->font, + x, y + font->y, (XftChar32*)wtext, len); + } else if (len==-1) { + wwarning(_("Conversion to widechar failed (possible invalid " + "multibyte sequence): '%s':(pos %d)\n"), + text, mtext-text+1); + /* we can draw normal text, or we can draw as much widechar + * text as was already converted until the error. go figure */ + /*XftDrawString8(scr->xftdraw, &textColor, font->font, + x, y + font->y, (XftChar8*)text, length);*/ + } + wfree(wtext); + } else if (font->screen->useMultiByte) { + XftDrawStringUtf8(scr->xftdraw, &textColor, font->font, + x, y + font->y, (XftChar8*)text, length); + } else { + XftDrawString8(scr->xftdraw, &textColor, font->font, + x, y + font->y, (XftChar8*)text, length); + } +} + + +WMFont* +WMCopyFontWithStyle(WMScreen *scrPtr, WMFont *font, WMFontStyle style) +{ + FcPattern *pattern; + WMFont *copy; + char *name; + + if (!font) + return NULL; + + pattern = FcNameParse(WMGetFontName(font)); + switch (style) { + case WFSNormal: + FcPatternDel(pattern, "weight"); + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "weight", "regular"); + FcPatternAddString(pattern, "weight", "medium"); + FcPatternAddString(pattern, "slant", "roman"); + break; + case WFSBold: + FcPatternDel(pattern, "weight"); + FcPatternAddString(pattern, "weight", "bold"); + break; + case WFSEmphasized: + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "slant", "italic"); + FcPatternAddString(pattern, "slant", "oblique"); + break; + case WFSBoldEmphasized: + FcPatternDel(pattern, "weight"); + FcPatternDel(pattern, "slant"); + FcPatternAddString(pattern, "weight", "bold"); + FcPatternAddString(pattern, "slant", "italic"); + FcPatternAddString(pattern, "slant", "oblique"); + break; + } + + name = FcNameUnparse(pattern); + copy = WMCreateFont(scrPtr, name); + FcPatternDestroy(pattern); + wfree(name); + + return copy; +} + + +#endif /* XFT */ + + diff --git a/WINGs/wfontpanel.c b/WINGs/wfontpanel.c index 5ee6bde8..48fe933f 100644 --- a/WINGs/wfontpanel.c +++ b/WINGs/wfontpanel.c @@ -9,6 +9,10 @@ #include #include +#ifdef XFT +#include +#include +#endif /* XXX TODO */ @@ -22,7 +26,7 @@ typedef struct W_FontPanel { WMFrame *upperF; WMTextField *sampleT; - + WMSplitView *split; WMFrame *lowerF; @@ -39,7 +43,7 @@ typedef struct W_FontPanel { WMButton *revertB; WMButton *setB; - + WMPropList *fdb; } FontPanel; @@ -65,24 +69,27 @@ typedef struct W_FontPanel { static int scalableFontSizes[] = { - 8, - 10, - 11, - 12, - 14, - 16, - 18, - 20, - 24, - 36, - 48, - 64 + 8, + 10, + 11, + 12, + 14, + 16, + 18, + 20, + 24, + 36, + 48, + 64 }; - -static void getSelectedFont(FontPanel *panel, char buffer[], int bufsize); +#ifdef XFT +static void setFontPanelFontName(FontPanel *panel, FcChar8 *family, FcChar8 *style, double size); +#endif + +static int isXLFD(char *font, int *length_ret); static void arrangeLowerFrame(FontPanel *panel); @@ -97,10 +104,10 @@ static void listFamilies(WMScreen *scr, WMFontPanel *panel); static void splitViewConstrainCallback(WMSplitView *sPtr, int indView, int *min, int *max) { - if (indView == 0) - *min = MIN_UPPER_HEIGHT; + if (indView == 0) + *min = MIN_UPPER_HEIGHT; else - *min = MIN_LOWER_HEIGHT; + *min = MIN_LOWER_HEIGHT; } static void @@ -110,42 +117,42 @@ notificationObserver(void *self, WMNotification *notif) void *object = WMGetNotificationObject(notif); if (WMGetNotificationName(notif) == WMViewSizeDidChangeNotification) { - if (object == WMWidgetView(panel->win)) { - int h = WMWidgetHeight(panel->win); - int w = WMWidgetWidth(panel->win); - - WMResizeWidget(panel->split, w, h-BUTTON_SPACE_HEIGHT); - - WMMoveWidget(panel->setB, w-80, h-(BUTTON_SPACE_HEIGHT-5)); - - WMMoveWidget(panel->revertB, w-240, h-(BUTTON_SPACE_HEIGHT-5)); - - } else if (object == WMWidgetView(panel->upperF)) { - - if (WMWidgetHeight(panel->upperF) < MIN_UPPER_HEIGHT) { - WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), - MIN_UPPER_HEIGHT); - } else { - WMResizeWidget(panel->sampleT, WMWidgetWidth(panel->upperF)-20, - WMWidgetHeight(panel->upperF)-10); - } - - } else if (object == WMWidgetView(panel->lowerF)) { - - if (WMWidgetHeight(panel->lowerF) < MIN_LOWER_HEIGHT) { - WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), - MIN_UPPER_HEIGHT); - - WMMoveWidget(panel->lowerF, 0, WMWidgetHeight(panel->upperF) - + WMGetSplitViewDividerThickness(panel->split)); - - WMResizeWidget(panel->lowerF, WMWidgetWidth(panel->lowerF), - WMWidgetWidth(panel->split) - MIN_UPPER_HEIGHT - - WMGetSplitViewDividerThickness(panel->split)); - } else { - arrangeLowerFrame(panel); - } - } + if (object == WMWidgetView(panel->win)) { + int h = WMWidgetHeight(panel->win); + int w = WMWidgetWidth(panel->win); + + WMResizeWidget(panel->split, w, h-BUTTON_SPACE_HEIGHT); + + WMMoveWidget(panel->setB, w-80, h-(BUTTON_SPACE_HEIGHT-5)); + + WMMoveWidget(panel->revertB, w-240, h-(BUTTON_SPACE_HEIGHT-5)); + + } else if (object == WMWidgetView(panel->upperF)) { + + if (WMWidgetHeight(panel->upperF) < MIN_UPPER_HEIGHT) { + WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), + MIN_UPPER_HEIGHT); + } else { + WMResizeWidget(panel->sampleT, WMWidgetWidth(panel->upperF)-20, + WMWidgetHeight(panel->upperF)-10); + } + + } else if (object == WMWidgetView(panel->lowerF)) { + + if (WMWidgetHeight(panel->lowerF) < MIN_LOWER_HEIGHT) { + WMResizeWidget(panel->upperF, WMWidgetWidth(panel->upperF), + MIN_UPPER_HEIGHT); + + WMMoveWidget(panel->lowerF, 0, WMWidgetHeight(panel->upperF) + + WMGetSplitViewDividerThickness(panel->split)); + + WMResizeWidget(panel->lowerF, WMWidgetWidth(panel->lowerF), + WMWidgetWidth(panel->split) - MIN_UPPER_HEIGHT + - WMGetSplitViewDividerThickness(panel->split)); + } else { + arrangeLowerFrame(panel); + } + } } } @@ -154,7 +161,7 @@ static void closeWindow(WMWidget *w, void *data) { FontPanel *panel = (FontPanel*)data; - + WMHideFontPanel(panel); } @@ -165,16 +172,16 @@ static void setClickedAction(WMWidget *w, void *data) { FontPanel *panel = (FontPanel*)data; - + if (panel->action) - (*panel->action)(panel, panel->data); + (*panel->action)(panel, panel->data); } static void revertClickedAction(WMWidget *w, void *data) { - FontPanel *panel = (FontPanel*)data; + /*FontPanel *panel = (FontPanel*)data;*/ /* XXX TODO */ } @@ -189,18 +196,19 @@ WMGetFontPanel(WMScreen *scr) int divThickness; if (scr->sharedFontPanel) - return scr->sharedFontPanel; + return scr->sharedFontPanel; panel = wmalloc(sizeof(FontPanel)); memset(panel, 0, sizeof(FontPanel)); - + panel->win = WMCreateWindow(scr, "fontPanel"); -/* WMSetWidgetBackgroundColor(panel->win, WMWhiteColor(scr));*/ + /* WMSetWidgetBackgroundColor(panel->win, WMWhiteColor(scr));*/ + WMSetWindowTitle(panel->win, _("Font Panel")); WMResizeWidget(panel->win, DEF_WIDTH, DEF_HEIGHT); WMSetWindowMinSize(panel->win, MIN_WIDTH, MIN_HEIGHT); WMSetViewNotifySizeChanges(WMWidgetView(panel->win), True); - + WMSetWindowCloseAction(panel->win, closeWindow, panel); panel->split = WMCreateSplitView(panel->win); @@ -213,7 +221,7 @@ WMGetFontPanel(WMScreen *scr) WMSetFrameRelief(panel->upperF, WRFlat); WMSetViewNotifySizeChanges(WMWidgetView(panel->upperF), True); panel->lowerF = WMCreateFrame(panel->win); -/* WMSetWidgetBackgroundColor(panel->lowerF, WMBlackColor(scr));*/ + /* WMSetWidgetBackgroundColor(panel->lowerF, WMBlackColor(scr));*/ WMSetFrameRelief(panel->lowerF, WRFlat); WMSetViewNotifySizeChanges(WMWidgetView(panel->lowerF), True); @@ -221,7 +229,7 @@ WMGetFontPanel(WMScreen *scr) WMAddSplitViewSubview(panel->split, W_VIEW(panel->lowerF)); WMResizeWidget(panel->upperF, DEF_WIDTH, DEF_UPPER_HEIGHT); - + WMResizeWidget(panel->lowerF, DEF_WIDTH, DEF_LOWER_HEIGHT); WMMoveWidget(panel->lowerF, 0, 60+divThickness); @@ -232,7 +240,7 @@ WMGetFontPanel(WMScreen *scr) panel->sampleT = WMCreateTextField(panel->upperF); WMResizeWidget(panel->sampleT, DEF_WIDTH - 20, 50); WMMoveWidget(panel->sampleT, 10, 10); - WMSetTextFieldText(panel->sampleT, _("Test!!!")); + WMSetTextFieldText(panel->sampleT, _("The quick brown fox jumps over the lazy dog")); font = WMBoldSystemFontOfSize(scr, 12); @@ -243,7 +251,7 @@ WMGetFontPanel(WMScreen *scr) WMSetLabelTextColor(panel->famL, white); WMSetLabelRelief(panel->famL, WRSunken); WMSetLabelTextAlignment(panel->famL, WACenter); - + panel->famLs = WMCreateList(panel->lowerF); WMSetListAction(panel->famLs, familyClick, panel); @@ -253,7 +261,7 @@ WMGetFontPanel(WMScreen *scr) WMSetLabelFont(panel->typL, font); WMSetLabelTextColor(panel->typL, white); WMSetLabelRelief(panel->typL, WRSunken); - WMSetLabelTextAlignment(panel->typL, WACenter); + WMSetLabelTextAlignment(panel->typL, WACenter); panel->typLs = WMCreateList(panel->lowerF); WMSetListAction(panel->typLs, typefaceClick, panel); @@ -267,7 +275,7 @@ WMGetFontPanel(WMScreen *scr) WMSetLabelTextAlignment(panel->sizL, WACenter); panel->sizT = WMCreateTextField(panel->lowerF); -/* WMSetTextFieldAlignment(panel->sizT, WARight);*/ + /* WMSetTextFieldAlignment(panel->sizT, WARight);*/ panel->sizLs = WMCreateList(panel->lowerF); WMSetListAction(panel->sizLs, sizeClick, panel); @@ -275,7 +283,7 @@ WMGetFontPanel(WMScreen *scr) WMReleaseFont(font); WMReleaseColor(white); WMReleaseColor(dark); - + panel->setB = WMCreateCommandButton(panel->win); WMResizeWidget(panel->setB, 70, 24); WMMoveWidget(panel->setB, 240, DEF_HEIGHT - (BUTTON_SPACE_HEIGHT-5)); @@ -304,20 +312,20 @@ WMGetFontPanel(WMScreen *scr) /* register notification observers */ - WMAddNotificationObserver(notificationObserver, panel, - WMViewSizeDidChangeNotification, - WMWidgetView(panel->win)); - WMAddNotificationObserver(notificationObserver, panel, - WMViewSizeDidChangeNotification, - WMWidgetView(panel->upperF)); - WMAddNotificationObserver(notificationObserver, panel, - WMViewSizeDidChangeNotification, - WMWidgetView(panel->lowerF)); + WMAddNotificationObserver(notificationObserver, panel, + WMViewSizeDidChangeNotification, + WMWidgetView(panel->win)); + WMAddNotificationObserver(notificationObserver, panel, + WMViewSizeDidChangeNotification, + WMWidgetView(panel->upperF)); + WMAddNotificationObserver(notificationObserver, panel, + WMViewSizeDidChangeNotification, + WMWidgetView(panel->lowerF)); listFamilies(scr, panel); - - + + return panel; } @@ -326,7 +334,7 @@ void WMFreeFontPanel(WMFontPanel *panel) { if (panel == WMWidgetScreen(panel->win)->sharedFontPanel) { - WMWidgetScreen(panel->win)->sharedFontPanel = NULL; + WMWidgetScreen(panel->win)->sharedFontPanel = NULL; } WMRemoveNotificationObserver(panel); WMUnmapWidget(panel->win); @@ -349,21 +357,6 @@ WMHideFontPanel(WMFontPanel *panel) } -void -WMSetFontPanelFont(WMFontPanel *panel, WMFont *font) -{ - -} - - -Bool -WMSetFontPanelFontName(WMFontPanel *panel, char *fontName) -{ - - return True; -} - - WMFont* WMGetFontPanelFont(WMFontPanel *panel) { @@ -371,19 +364,38 @@ WMGetFontPanelFont(WMFontPanel *panel) } -char* -WMGetFontPanelFontName(WMFontPanel *panel) +void +WMSetFontPanelFont(WMFontPanel *panel, char *fontName) { - char name[512]; +#ifdef XFT + int fname_len; + FcPattern *pattern; + FcChar8 *family, *style; + double size; + + if (!isXLFD(fontName, &fname_len)) { + /* maybe its proper fontconfig and we can parse it */ + pattern = FcNameParse(fontName); + } else { + /* maybe its proper xlfd and we can convert it to an FcPattern */ + pattern = XftXlfdParse(fontName, False, False); + //FcPatternPrint(pattern); + } - getSelectedFont(panel, name, sizeof(name)); + if (!pattern) + return; - return wstrdup(name); -} + if (FcPatternGetString(pattern, FC_FAMILY, 0, &family)==FcResultMatch) + if (FcPatternGetString(pattern, FC_STYLE, 0, &style)==FcResultMatch) + if (FcPatternGetDouble(pattern, "pixelsize", 0, &size)==FcResultMatch) + setFontPanelFontName(panel, family, style, size); + FcPatternDestroy(pattern); +#endif +} -void +void WMSetFontPanelAction(WMFontPanel *panel, WMAction2 *action, void *data) { panel->action = action; @@ -404,7 +416,7 @@ arrangeLowerFrame(FontPanel *panel) #define LABEL_HEIGHT 20 height -= WMGetSplitViewDividerThickness(panel->split); - + height -= LABEL_HEIGHT + 8; @@ -458,6 +470,22 @@ arrangeLowerFrame(FontPanel *panel) +static int +isXLFD(char *font, int *length_ret) +{ + int c = 0; + + *length_ret = 0; + while (*font) { + (*length_ret)++; + if (*font++ == '-') + c++; + } + + return c==NUM_FIELDS; +} + +#ifndef XFT static Bool parseFont(char *font, char values[NUM_FIELDS][256]) { @@ -470,40 +498,24 @@ parseFont(char *font, char values[NUM_FIELDS][256]) ptr++; /* skip first - */ bptr = buffer; while (*ptr) { - if (*ptr == '-') { - *bptr = 0; - strcpy(values[part], buffer); - bptr = buffer; - part++; - } else { - *bptr++ = *ptr; - } - ptr++; + if (*ptr == '-') { + *bptr = 0; + strcpy(values[part], buffer); + bptr = buffer; + part++; + } else { + *bptr++ = *ptr; + } + ptr++; } *bptr = 0; strcpy(values[part], buffer); - + return True; } -static int -isXLFD(char *font, int *length_ret) -{ - int c = 0; - - *length_ret = 0; - while (*font) { - (*length_ret)++; - if (*font++ == '-') - c++; - } - - return c==NUM_FIELDS; -} - - typedef struct { @@ -512,10 +524,10 @@ typedef struct { char *setWidth; char *addStyle; - + char showSetWidth; /* when duplicated */ char showAddStyle; /* when duplicated */ - + WMArray *sizes; } Typeface; @@ -531,6 +543,18 @@ typedef struct { WMArray *typefaces; } Family; +#endif +#ifdef XFT +typedef struct { + char *typeface; + WMArray *sizes; +} Xft_Typeface; + +typedef struct { + char *name; /* gotta love simplicity */ + WMArray *typefaces; +} Xft_Family; +#endif @@ -542,38 +566,69 @@ compare_int(const void *a, const void *b) int i2 = *(int*)b; if (i1 < i2) - return -1; + return -1; else if (i1 > i2) - return 1; + return 1; else - return 0; + return 0; } - static void +#ifdef XFT +addSizeToTypeface(Xft_Typeface *face, int size) +#else addSizeToTypeface(Typeface *face, int size) +#endif { if (size == 0) { - int j; - - for (j = 0; j < sizeof(scalableFontSizes)/sizeof(int); j++) { - size = scalableFontSizes[j]; - - if (!WMCountInArray(face->sizes, (void*)size)) { - WMAddToArray(face->sizes, (void*)size); - } - } - WMSortArray(face->sizes, compare_int); + int j; + + for (j = 0; j < sizeof(scalableFontSizes)/sizeof(int); j++) { + size = scalableFontSizes[j]; + + if (!WMCountInArray(face->sizes, (void*)size)) { + WMAddToArray(face->sizes, (void*)size); + } + } + WMSortArray(face->sizes, compare_int); } else { - if (!WMCountInArray(face->sizes, (void*)size)) { - WMAddToArray(face->sizes, (void*)size); - WMSortArray(face->sizes, compare_int); - } + if (!WMCountInArray(face->sizes, (void*)size)) { + WMAddToArray(face->sizes, (void*)size); + WMSortArray(face->sizes, compare_int); + } } } +#ifdef XFT +static void +addTypefaceToXftFamily(Xft_Family *fam, char *style) +{ + Xft_Typeface *face; + WMArrayIterator i; + + if(fam->typefaces) { + WM_ITERATE_ARRAY(fam->typefaces, face, i) { + if(strcmp(face->typeface, style) != 0) + continue; /* go to next interation */ + addSizeToTypeface(face, 0); + return; + } + } else { + fam->typefaces = WMCreateArray(4); + } + + face = wmalloc(sizeof(Xft_Typeface)); + memset(face, 0 , sizeof(Xft_Typeface)); + face->typeface = wstrdup(style); + face->sizes = WMCreateArray(4); + addSizeToTypeface(face, 0); + + WMAddToArray(fam->typefaces, face); +} + +#else /* XFT */ static void addTypefaceToFamily(Family *family, char fontFields[NUM_FIELDS][256]) @@ -583,23 +638,23 @@ addTypefaceToFamily(Family *family, char fontFields[NUM_FIELDS][256]) if (family->typefaces) { WM_ITERATE_ARRAY(family->typefaces, face, i) { - int size; + int size; - if (strcmp(face->weight, fontFields[WEIGHT]) != 0) { - continue; - } - if (strcmp(face->slant, fontFields[SLANT]) != 0) { - continue; - } + if (strcmp(face->weight, fontFields[WEIGHT]) != 0) { + continue; + } + if (strcmp(face->slant, fontFields[SLANT]) != 0) { + continue; + } - size = atoi(fontFields[PIXEL_SIZE]); + size = atoi(fontFields[PIXEL_SIZE]); - addSizeToTypeface(face, size); + addSizeToTypeface(face, size); - return; - } + return; + } } else { - family->typefaces = WMCreateArray(4); + family->typefaces = WMCreateArray(4); } face = wmalloc(sizeof(Typeface)); @@ -615,14 +670,47 @@ addTypefaceToFamily(Family *family, char fontFields[NUM_FIELDS][256]) WMAddToArray(family->typefaces, face); } - +#endif /* * families (same family name) (Hashtable of family -> array) * registries (same family but different registries) - * + * */ +#ifdef XFT +static void +addFontToXftFamily(WMHashTable *families, char *name, char *style) +{ + WMArrayIterator i; + WMArray *array; + Xft_Family *fam; + + array = WMHashGet(families, name); + if(array) { + WM_ITERATE_ARRAY(array, fam, i) { + if(strcmp(fam->name, name) == 0 ) + addTypefaceToXftFamily(fam, style); + return; + } + } + + array = WMCreateArray(8); + + fam = wmalloc(sizeof(Xft_Family)); + memset(fam, 0, sizeof(Xft_Family)); + + fam->name = wstrdup(name); + + addTypefaceToXftFamily(fam, style); + + WMAddToArray(array, fam); + + WMHashInsert(families, fam->name, array); +} + +#else /* XFT */ + static void addFontToFamily(WMHashTable *families, char fontFields[NUM_FIELDS][256]) { @@ -632,87 +720,87 @@ addFontToFamily(WMHashTable *families, char fontFields[NUM_FIELDS][256]) family = WMHashGet(families, fontFields[FAMILY]); - + if (family) { - /* look for same encoding/registry and foundry */ + /* look for same encoding/registry and foundry */ WM_ITERATE_ARRAY(family, fam, i) { - int enc, reg, found; - - enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0); - reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0); - found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0); - - if (enc && reg && found) { - addTypefaceToFamily(fam, fontFields); - return; - } - } - /* look for same encoding/registry */ + int enc, reg, found; + + enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0); + reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0); + found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0); + + if (enc && reg && found) { + addTypefaceToFamily(fam, fontFields); + return; + } + } + /* look for same encoding/registry */ WM_ITERATE_ARRAY(family, fam, i) { - int enc, reg; - - enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0); - reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0); - - if (enc && reg) { - /* has the same encoding, but the foundry is different */ - fam->showFoundry = 1; - - fam = wmalloc(sizeof(Family)); - memset(fam, 0, sizeof(Family)); - - fam->name = wstrdup(fontFields[FAMILY]); - fam->foundry = wstrdup(fontFields[FOUNDRY]); - fam->registry = wstrdup(fontFields[REGISTRY]); - fam->encoding = wstrdup(fontFields[ENCODING]); - fam->showFoundry = 1; - - addTypefaceToFamily(fam, fontFields); - - WMAddToArray(family, fam); - return; - } - } - /* look for same foundry */ + int enc, reg; + + enc = (strcmp(fam->encoding, fontFields[ENCODING]) == 0); + reg = (strcmp(fam->registry, fontFields[REGISTRY]) == 0); + + if (enc && reg) { + /* has the same encoding, but the foundry is different */ + fam->showFoundry = 1; + + fam = wmalloc(sizeof(Family)); + memset(fam, 0, sizeof(Family)); + + fam->name = wstrdup(fontFields[FAMILY]); + fam->foundry = wstrdup(fontFields[FOUNDRY]); + fam->registry = wstrdup(fontFields[REGISTRY]); + fam->encoding = wstrdup(fontFields[ENCODING]); + fam->showFoundry = 1; + + addTypefaceToFamily(fam, fontFields); + + WMAddToArray(family, fam); + return; + } + } + /* look for same foundry */ WM_ITERATE_ARRAY(family, fam, i) { - int found; - - found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0); - - if (found) { - /* has the same foundry, but encoding is different */ - fam->showRegistry = 1; - - fam = wmalloc(sizeof(Family)); - memset(fam, 0, sizeof(Family)); - - fam->name = wstrdup(fontFields[FAMILY]); - fam->foundry = wstrdup(fontFields[FOUNDRY]); - fam->registry = wstrdup(fontFields[REGISTRY]); - fam->encoding = wstrdup(fontFields[ENCODING]); - fam->showRegistry = 1; - - addTypefaceToFamily(fam, fontFields); - - WMAddToArray(family, fam); - return; - } - } - /* foundry and encoding do not match anything known */ - fam = wmalloc(sizeof(Family)); - memset(fam, 0, sizeof(Family)); - - fam->name = wstrdup(fontFields[FAMILY]); - fam->foundry = wstrdup(fontFields[FOUNDRY]); - fam->registry = wstrdup(fontFields[REGISTRY]); - fam->encoding = wstrdup(fontFields[ENCODING]); - fam->showFoundry = 1; - fam->showRegistry = 1; - - addTypefaceToFamily(fam, fontFields); - - WMAddToArray(family, fam); - return; + int found; + + found = (strcmp(fam->foundry, fontFields[FOUNDRY]) == 0); + + if (found) { + /* has the same foundry, but encoding is different */ + fam->showRegistry = 1; + + fam = wmalloc(sizeof(Family)); + memset(fam, 0, sizeof(Family)); + + fam->name = wstrdup(fontFields[FAMILY]); + fam->foundry = wstrdup(fontFields[FOUNDRY]); + fam->registry = wstrdup(fontFields[REGISTRY]); + fam->encoding = wstrdup(fontFields[ENCODING]); + fam->showRegistry = 1; + + addTypefaceToFamily(fam, fontFields); + + WMAddToArray(family, fam); + return; + } + } + /* foundry and encoding do not match anything known */ + fam = wmalloc(sizeof(Family)); + memset(fam, 0, sizeof(Family)); + + fam->name = wstrdup(fontFields[FAMILY]); + fam->foundry = wstrdup(fontFields[FOUNDRY]); + fam->registry = wstrdup(fontFields[REGISTRY]); + fam->encoding = wstrdup(fontFields[ENCODING]); + fam->showFoundry = 1; + fam->showRegistry = 1; + + addTypefaceToFamily(fam, fontFields); + + WMAddToArray(family, fam); + return; } family = WMCreateArray(8); @@ -724,87 +812,140 @@ addFontToFamily(WMHashTable *families, char fontFields[NUM_FIELDS][256]) fam->foundry = wstrdup(fontFields[FOUNDRY]); fam->registry = wstrdup(fontFields[REGISTRY]); fam->encoding = wstrdup(fontFields[ENCODING]); - + addTypefaceToFamily(fam, fontFields); - + WMAddToArray(family, fam); WMHashInsert(families, fam->name, family); } +#endif /* XFT */ static void listFamilies(WMScreen *scr, WMFontPanel *panel) { +#ifdef XFT + FcObjectSet *os = 0; + FcFontSet *fs; + FcPattern *pat; +#else /* XFT */ char **fontList; - WMHashTable *families; char fields[NUM_FIELDS][256]; + int count; +#endif /* XFT */ + WMHashTable *families; WMHashEnumerator enumer; WMArray *array; - int i, count; - - fontList = XListFonts(scr->display, ALL_FONTS_MASK, MAX_FONTS_TO_RETRIEVE, + int i; + +#ifdef XFT + pat = FcPatternCreate(); + os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, 0); + fs = FcFontList(0, pat, os); + if (!fs) { + WMRunAlertPanel(scr, panel->win, _("Error"), + _("Could not init font config library\n"), _("OK"), NULL, NULL); + return; + } + if (pat) + FcPatternDestroy (pat); +#else /* XFT */ + fontList = XListFonts(scr->display, ALL_FONTS_MASK, MAX_FONTS_TO_RETRIEVE, &count); if (!fontList) { - WMRunAlertPanel(scr, panel->win, _("Error"), - _("Could not retrieve font list"), _("OK"), NULL, NULL); - return; + WMRunAlertPanel(scr, panel->win, _("Error"), + _("Could not retrieve font list"), _("OK"), NULL, NULL); + return; } +#endif /* XFT */ families = WMCreateHashTable(WMStringPointerHashCallbacks); +#ifdef XFT + if(fs) { + for (i = 0; i < fs->nfont; i++) { + FcChar8 *family; + FcChar8 *style; + + if (FcPatternGetString(fs->fonts[i],FC_FAMILY,0,&family)==FcResultMatch) + if (FcPatternGetString(fs->fonts[i],FC_STYLE,0,&style)==FcResultMatch) + addFontToXftFamily(families, family, style); + } + FcFontSetDestroy(fs); + } +#else /* XFT */ for (i = 0; i < count; i++) { - int fname_len; - - if (!isXLFD(fontList[i], &fname_len)) { - *fontList[i] = '\0'; - continue; - } - if (fname_len > 255) { - wwarning(_("font name %s is longer than 256, which is invalid."), - fontList[i]); - *fontList[i] = '\0'; - continue; - } - if (!parseFont(fontList[i], fields)) { - *fontList[i] = '\0'; - continue; - } - addFontToFamily(families, fields); + int fname_len; + + if (!isXLFD(fontList[i], &fname_len)) { + *fontList[i] = '\0'; + continue; + } + if (fname_len > 255) { + wwarning(_("font name %s is longer than 256, which is invalid."), + fontList[i]); + *fontList[i] = '\0'; + continue; + } + if (!parseFont(fontList[i], fields)) { + *fontList[i] = '\0'; + continue; + } + addFontToFamily(families, fields); } +#endif /* XFT */ enumer = WMEnumerateHashTable(families); - + +#ifdef XFT while ((array = WMNextHashEnumeratorItem(&enumer))) { - WMArrayIterator i; - Family *fam; - char buffer[256]; - WMListItem *item; + WMArrayIterator i; + Xft_Family *fam; + char buffer[256]; + WMListItem *item; WM_ITERATE_ARRAY(array, fam, i) { - strcpy(buffer, fam->name); - - if (fam->showFoundry) { - strcat(buffer, " "); - strcat(buffer, fam->foundry); - strcat(buffer, " "); - } - if (fam->showRegistry) { - strcat(buffer, " ("); - strcat(buffer, fam->registry); - strcat(buffer, "-"); - strcat(buffer, fam->encoding); - strcat(buffer, ")"); - } - item = WMAddListItem(panel->famLs, buffer); - - item->clientData = fam; - } + strcpy(buffer, fam->name); + item = WMAddListItem(panel->famLs, buffer); + + item->clientData = fam; + } + WMFreeArray(array); } +#else /* XFT */ + while ((array = WMNextHashEnumeratorItem(&enumer))) { + WMArrayIterator i; + Family *fam; + char buffer[256]; + WMListItem *item; + + WM_ITERATE_ARRAY(array, fam, i) { + strcpy(buffer, fam->name); + + if (fam->showFoundry) { + strcat(buffer, " "); + strcat(buffer, fam->foundry); + strcat(buffer, " "); + } + if (fam->showRegistry) { + strcat(buffer, " ("); + strcat(buffer, fam->registry); + strcat(buffer, "-"); + strcat(buffer, fam->encoding); + strcat(buffer, ")"); + } + item = WMAddListItem(panel->famLs, buffer); + + item->clientData = fam; + } + WMFreeArray(array); + } +#endif /* XFT */ WMSortListItems(panel->famLs); - + WMFreeHashTable(families); } @@ -813,23 +954,42 @@ static void getSelectedFont(FontPanel *panel, char buffer[], int bufsize) { WMListItem *item; +#ifdef XFT + Xft_Family *family; + Xft_Typeface *face; +#else Family *family; Typeface *face; +#endif char *size; - + item = WMGetListSelectedItem(panel->famLs); if (!item) - return; + return; +#ifdef XFT + family = (Xft_Family*)item->clientData; +#else family = (Family*)item->clientData; +#endif item = WMGetListSelectedItem(panel->typLs); if (!item) - return; + return; +#ifdef XFT + face = (Xft_Typeface*)item->clientData; +#else face = (Typeface*)item->clientData; +#endif size = WMGetTextFieldText(panel->sizT); +#ifdef XFT + snprintf(buffer, bufsize, "%s:style=%s:pixelsize=%s", + family->name, + face->typeface, + size); +#else snprintf(buffer, bufsize, "-%s-%s-%s-%s-%s-%s-%s-*-*-*-*-*-%s-%s", family->foundry, family->name, @@ -840,7 +1000,7 @@ getSelectedFont(FontPanel *panel, char buffer[], int bufsize) size, family->registry, family->encoding); - +#endif /* XFT */ wfree(size); } @@ -851,26 +1011,30 @@ preview(FontPanel *panel) { char buffer[512]; WMFont *font; - + getSelectedFont(panel, buffer, sizeof(buffer)); - font = WMCreateFont(WMWidgetScreen(panel->win), buffer); if (font) { - WMSetTextFieldFont(panel->sampleT, font); - WMReleaseFont(font); + WMSetTextFieldFont(panel->sampleT, font); + WMReleaseFont(font); } } -static void +static void familyClick(WMWidget *w, void *data) { WMList *lPtr = (WMList*)w; WMListItem *item; +#ifdef XFT + Xft_Family *family; + Xft_Typeface *face; +#else Family *family; - FontPanel *panel = (FontPanel*)data; Typeface *face; +#endif + FontPanel *panel = (FontPanel*)data; WMArrayIterator i; /* current typeface and size */ char *oface = NULL; @@ -881,92 +1045,107 @@ familyClick(WMWidget *w, void *data) /* must try to keep the same typeface and size for the new family */ item = WMGetListSelectedItem(panel->typLs); if (item) - oface = wstrdup(item->text); + oface = wstrdup(item->text); osize = WMGetTextFieldText(panel->sizT); item = WMGetListSelectedItem(lPtr); +#ifdef XFT + family = (Xft_Family*)item->clientData; +#else family = (Family*)item->clientData; +#endif WMClearList(panel->typLs); WM_ITERATE_ARRAY(family->typefaces, face, i) { - char buffer[256]; - int top=0; - WMListItem *fitem; - - if (strcmp(face->weight, "medium") == 0) { - buffer[0] = 0; - } else { - if (*face->weight) { - strcpy(buffer, face->weight); - buffer[0] = toupper(buffer[0]); - strcat(buffer, " "); - } else { - buffer[0] = 0; - } - } - - if (strcmp(face->slant, "r") == 0) { - strcat(buffer, _("Roman")); - top = 1; - } else if (strcmp(face->slant, "i") == 0) { - strcat(buffer, _("Italic")); - } else if (strcmp(face->slant, "o") == 0) { - strcat(buffer, _("Oblique")); - } else if (strcmp(face->slant, "ri") == 0) { - strcat(buffer, _("Rev Italic")); - } else if (strcmp(face->slant, "ro") == 0) { - strcat(buffer, _("Rev Oblique")); - } else { - strcat(buffer, face->slant); - } - - if (buffer[0] == 0) { - strcpy(buffer, _("Normal")); - } - - if (top) - fitem = WMInsertListItem(panel->typLs, 0, buffer); - else - fitem = WMAddListItem(panel->typLs, buffer); - fitem->clientData = face; + char buffer[256]; + int top=0; + WMListItem *fitem; + +#ifdef XFT + strcpy(buffer, face->typeface); + if(strcasecmp(face->typeface, "Roman") == 0) + top = 1; + if(strcasecmp(face->typeface, "Regular") == 0) + top = 1; +#else + if (strcmp(face->weight, "medium") == 0) { + buffer[0] = 0; + } else { + if (*face->weight) { + strcpy(buffer, face->weight); + buffer[0] = toupper(buffer[0]); + strcat(buffer, " "); + } else { + buffer[0] = 0; + } + } + + if (strcmp(face->slant, "r") == 0) { + strcat(buffer, _("Roman")); + top = 1; + } else if (strcmp(face->slant, "i") == 0) { + strcat(buffer, _("Italic")); + } else if (strcmp(face->slant, "o") == 0) { + strcat(buffer, _("Oblique")); + } else if (strcmp(face->slant, "ri") == 0) { + strcat(buffer, _("Rev Italic")); + } else if (strcmp(face->slant, "ro") == 0) { + strcat(buffer, _("Rev Oblique")); + } else { + strcat(buffer, face->slant); + } + + if (buffer[0] == 0) { + strcpy(buffer, _("Normal")); + } +#endif + if (top) + fitem = WMInsertListItem(panel->typLs, 0, buffer); + else + fitem = WMAddListItem(panel->typLs, buffer); + fitem->clientData = face; } if (oface) { - facei = WMFindRowOfListItemWithTitle(panel->typLs, oface); - wfree(oface); + facei = WMFindRowOfListItemWithTitle(panel->typLs, oface); + wfree(oface); } if (facei < 0) { - facei = 0; + facei = 0; } WMSelectListItem(panel->typLs, facei); typefaceClick(panel->typLs, panel); - + if (osize) { - sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize); + sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize); } if (sizei >= 0) { - WMSelectListItem(panel->sizLs, sizei); - sizeClick(panel->sizLs, panel); + WMSelectListItem(panel->sizLs, sizei); + sizeClick(panel->sizLs, panel); } if (osize) - wfree(osize); + wfree(osize); preview(panel); } -static void +static void typefaceClick(WMWidget *w, void *data) { FontPanel *panel = (FontPanel*)data; WMListItem *item; +#ifdef XFT + Xft_Typeface *face; +#else Typeface *face; +#endif WMArrayIterator i; char buffer[32]; @@ -978,50 +1157,138 @@ typefaceClick(WMWidget *w, void *data) item = WMGetListSelectedItem(panel->typLs); +#ifdef XFT + face = (Xft_Typeface*)item->clientData; +#else face = (Typeface*)item->clientData; - +#endif + WMClearList(panel->sizLs); WM_ITERATE_ARRAY(face->sizes, size, i) { - if ((int)size != 0) { - sprintf(buffer, "%i", (int)size); + if ((int)size != 0) { + sprintf(buffer, "%i", (int)size); - WMAddListItem(panel->sizLs, buffer); - } + WMAddListItem(panel->sizLs, buffer); + } } if (osize) { - sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize); + sizei = WMFindRowOfListItemWithTitle(panel->sizLs, osize); } if (sizei < 0) { - sizei = WMFindRowOfListItemWithTitle(panel->sizLs, "12"); + sizei = WMFindRowOfListItemWithTitle(panel->sizLs, "12"); } if (sizei < 0) { - sizei = 0; + sizei = 0; } WMSelectListItem(panel->sizLs, sizei); WMSetListPosition(panel->sizLs, sizei); sizeClick(panel->sizLs, panel); if (osize) - wfree(osize); + wfree(osize); preview(panel); } - -static void +static void sizeClick(WMWidget *w, void *data) { FontPanel *panel = (FontPanel*)data; WMListItem *item; - - item = WMGetListSelectedItem(panel->sizLs); + item = WMGetListSelectedItem(panel->sizLs); WMSetTextFieldText(panel->sizT, item->text); - + WMSelectTextFieldRange(panel->sizT, wmkrange(0, strlen(item->text))); preview(panel); } + +#ifdef XFT +static void +setFontPanelFontName(FontPanel *panel, FcChar8 *family, FcChar8 *style, double size) +{ + int famrow; + int stlrow; + int sz; + char asize[64]; + void *vsize; + WMListItem *item; + Xft_Family *fam; + Xft_Typeface *face; + WMArrayIterator i; + + famrow = WMFindRowOfListItemWithTitle(panel->famLs, family); + if (famrow < 0 ){ + famrow = 0; + return; + } + WMSelectListItem(panel->famLs, famrow); + WMSetListPosition(panel->famLs, famrow); + + WMClearList(panel->typLs); + + item = WMGetListSelectedItem(panel->famLs); + + fam = (Xft_Family*)item->clientData; + WM_ITERATE_ARRAY(fam->typefaces, face, i) { + char buffer[256]; + int top=0; + WMListItem *fitem; + + strcpy(buffer, face->typeface); + if(strcasecmp(face->typeface, "Roman") == 0) + top = 1; + if (top) + fitem = WMInsertListItem(panel->typLs, 0, buffer); + else + fitem = WMAddListItem(panel->typLs, buffer); + fitem->clientData = face; + } + + + stlrow = WMFindRowOfListItemWithTitle(panel->typLs, style); + + if (stlrow < 0) { + stlrow = 0; + return; + } + + WMSelectListItem(panel->typLs, stlrow); + + item = WMGetListSelectedItem(panel->typLs); + + face = (Xft_Typeface*)item->clientData; + + WMClearList(panel->sizLs); + + + WM_ITERATE_ARRAY(face->sizes, vsize, i) { + char buffer[32]; + if ((int)vsize != 0) { + sprintf(buffer, "%i", (int)vsize); + + WMAddListItem(panel->sizLs, buffer); + } + } + + snprintf(asize, sizeof(asize)-1, "%d",(int)(size+0.5)); + + sz = WMFindRowOfListItemWithTitle(panel->sizLs, asize); + + if (sz < 0) { + sz = 4; + return; + } + + WMSelectListItem(panel->sizLs, sz); + sizeClick(panel->sizLs, panel); + + return; +} + +#endif + diff --git a/WINGs/wframe.c b/WINGs/wframe.c index 60d5959b..5d286c96 100644 --- a/WINGs/wframe.c +++ b/WINGs/wframe.c @@ -149,6 +149,7 @@ paintFrame(Frame *fPtr) drawTitle = True; } else { + tw = tx = 0; drawTitle = False; } @@ -160,6 +161,11 @@ paintFrame(Frame *fPtr) region = XCreateRegion(); + rect.x = 0; + rect.y = 0; + rect.width = view->size.width; + rect.height = view->size.height; + XUnionRectWithRegion(&rect, region, region); if (drawTitle) { tmp = XCreateRegion(); rect.x = tx; @@ -167,13 +173,6 @@ paintFrame(Frame *fPtr) rect.width = tw; rect.height = th; XUnionRectWithRegion(&rect, tmp, tmp); - } - rect.x = 0; - rect.y = 0; - rect.width = view->size.width; - rect.height = view->size.height; - XUnionRectWithRegion(&rect, region, region); - if (drawTitle) { XSubtractRegion(region, tmp, region); XDestroyRegion(tmp); } diff --git a/WINGs/widgets.c b/WINGs/widgets.c index f06bdafd..1bc5b6e3 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -12,6 +12,8 @@ #include #include +#include + /********** data ************/ @@ -591,6 +593,7 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) "WM_STATE" }; Atom atoms[sizeof(atomNames)/sizeof(char*)]; + char *locale; int i; if (!initialized) { @@ -756,16 +759,20 @@ WMCreateScreenWithRContext(Display *display, int screen, RContext *context) scrPtr->stipple = stipple; scrPtr->useMultiByte = WINGsConfiguration.useMultiByte; + scrPtr->useMultiByte = 0; - scrPtr->useWideChar = 1; + locale = setlocale(LC_CTYPE, NULL); + //printf("LC_CTYPE=%s\n", locale); + if (!locale || strcmp(locale, "C")==0 || strcmp(locale, "POSIX")==0) + scrPtr->useWideChar = 0; + else + scrPtr->useWideChar = 1; scrPtr->antialiasedText = WINGsConfiguration.antialiasedText; - scrPtr->normalFont = WMSystemFontOfSize(scrPtr, - WINGsConfiguration.defaultFontSize); + scrPtr->normalFont = WMSystemFontOfSize(scrPtr, 0); - scrPtr->boldFont = WMBoldSystemFontOfSize(scrPtr, - WINGsConfiguration.defaultFontSize); + scrPtr->boldFont = WMBoldSystemFontOfSize(scrPtr, 0); if (!scrPtr->boldFont) scrPtr->boldFont = scrPtr->normalFont; diff --git a/WINGs/winputmethod.c b/WINGs/winputmethod.c index c0ed4ef8..eb91211d 100644 --- a/WINGs/winputmethod.c +++ b/WINGs/winputmethod.c @@ -22,7 +22,8 @@ typedef struct W_ICContext { -Bool W_InitIMStuff(WMScreen *scr) +Bool +W_InitIMStuff(WMScreen *scr) { WMIMContext *ctx; @@ -38,7 +39,8 @@ Bool W_InitIMStuff(WMScreen *scr) } -void W_CloseIMStuff(WMScreen *scr) +void +W_CloseIMStuff(WMScreen *scr) { if (!scr->imctx) return; @@ -51,7 +53,8 @@ void W_CloseIMStuff(WMScreen *scr) -WMICContext *W_CreateIC(WMView *view) +WMICContext* +W_CreateIC(WMView *view) { WMScreen *scr = W_VIEW_SCREEN(view); WMICContext *ctx; @@ -60,11 +63,12 @@ WMICContext *W_CreateIC(WMView *view) ctx->next = scr->imctx->icList; if (scr->imctx->icList) scr->imctx->icList->prev = ctx; - scr->imctx = ctx; + //scr->imctx = ctx; } -void W_DestroyIC(WMICContext *ctx) +void +W_DestroyIC(WMICContext *ctx) { XDestroyIC(ctx->xic); @@ -72,8 +76,9 @@ void W_DestroyIC(WMICContext *ctx) } -int W_LookupString(WMView *view, XKeyEvent *event, - char buffer, int bufsize, KeySym ksym) +int +W_LookupString(WMView *view, XKeyEvent *event, + char buffer, int bufsize, KeySym ksym) { } diff --git a/WINGs/wmisc.c b/WINGs/wmisc.c index f8bfdb47..41e50791 100644 --- a/WINGs/wmisc.c +++ b/WINGs/wmisc.c @@ -30,26 +30,26 @@ W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y, unsigned int width, case WRSimple: XDrawRectangle(dpy, d, black, x, y, width-1, height-1); return; - + case WRRaised: bgc = black; dgc = dark; wgc = white; lgc = light; break; - + case WRSunken: wgc = dark; lgc = black; bgc = white; dgc = light; break; - + case WRPushed: lgc = wgc = black; dgc = bgc = white; break; - + case WRRidge: lgc = bgc = dark; dgc = wgc = white; @@ -59,7 +59,7 @@ W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y, unsigned int width, wgc = dgc = dark; lgc = bgc = white; break; - + default: return; } @@ -68,12 +68,12 @@ W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y, unsigned int width, if (width > 2 && relief != WRRaised && relief!=WRPushed) { XDrawLine(dpy, d, lgc, x+1, y+1, x+width-3, y+1); } - + XDrawLine(dpy, d, wgc, x, y, x, y+height-1); if (height > 2 && relief != WRRaised && relief!=WRPushed) { XDrawLine(dpy, d, lgc, x+1, y+1, x+1, y+height-3); } - + /* bottom right */ XDrawLine(dpy, d, bgc, x, y+height-1, x+width-1, y+height-1); if (width > 2 && relief!=WRPushed) { @@ -87,22 +87,82 @@ W_DrawReliefWithGC(W_Screen *scr, Drawable d, int x, int y, unsigned int width, } +static int +findNextWord(char *text, int limit) +{ + int pos, len; + + len = strcspn(text, " \t\n\r"); + pos = len + strspn(text+len, " \t\n\r"); + if (pos > limit) + pos = limit; + + return pos; +} static int fitText(char *text, WMFont *font, int width, int wrap) { + int i, w, beforecrlf, word1, word2; + + /* text length before first cr/lf */ + beforecrlf = strcspn(text, "\n\r"); + + if (!wrap || beforecrlf==0) + return beforecrlf; + + w = WMWidthOfString(font, text, beforecrlf); + if (w <= width) { + /* text up to first crlf fits */ + return beforecrlf; + } + + word1 = 0; + while (1) { + word2 = word1 + findNextWord(text+word1, beforecrlf-word1); + if (word2 >= beforecrlf) + break; + w = WMWidthOfString(font, text, word2); + if (w > width) + break; + word1 = word2; + } + + for (i=word1; i width) { + break; + } + } + + /* keep words complete if possible */ + if (!isspace(text[i]) && word1>0) { + i = word1; + } else if (isspace(text[i]) && idisplay, view->window, + d = XCreatePixmap(screen->display, view->window, view->size.width, view->size.height, screen->depth); #endif @@ -215,7 +275,7 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, #ifndef DOUBLE_BUFFER XClearWindow(screen->display, d); #else - XSetForeground(screen->display, screen->copyGC, + XSetForeground(screen->display, screen->copyGC, view->attribs.background_pixel); XFillRectangle(screen->display, d, screen->copyGC, 0, 0, view->size.width, view->size.height); @@ -232,7 +292,7 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, x = 1; y = 1; w = view->size.width - 3; - h = view->size.height - 3; + h = view->size.height - 3; } /* calc. image alignment */ @@ -247,7 +307,7 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, y = 0; */ break; - + case WIPLeft: ix = x; iy = y + (h - image->height) / 2; @@ -255,20 +315,20 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, y = 0; w -= image->width + 5; break; - + case WIPRight: ix = view->size.width - image->width - x; iy = y + (h - image->height) / 2; w -= image->width + 5; break; - + case WIPBelow: ix = (view->size.width - image->width) / 2; iy = h - image->height; y = 0; h -= image->height; break; - + default: case WIPAbove: ix = (view->size.width - image->width) / 2; @@ -277,7 +337,7 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, h -= image->height; break; } - + ix += ofs; iy += ofs; @@ -295,7 +355,7 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, /* draw text */ if (position != WIPImageOnly && text!=NULL) { int textHeight; - + textHeight = W_GetTextHeight(font, text, w-8, wrap); W_PaintText(view, d, font, x+ofs+4, y+ofs + (h-textHeight)/2, w-8, alignment, textColor, wrap, text, strlen(text)); @@ -314,26 +374,26 @@ W_PaintTextAndImage(W_View *view, int wrap, WMColor *textColor, W_Font *font, -WMPoint +WMPoint wmkpoint(int x, int y) { WMPoint point; - + point.x = x; point.y = y; - + return point; } -WMSize +WMSize wmksize(unsigned int width, unsigned int height) { WMSize size; - + size.width = width; size.height = height; - + return size; } diff --git a/WINGs/wscroller.c b/WINGs/wscroller.c index 4ddbd38e..263848aa 100644 --- a/WINGs/wscroller.c +++ b/WINGs/wscroller.c @@ -306,10 +306,9 @@ paintArrow(WMScroller *sPtr, Drawable d, int part) gc = scr->whiteGC; #endif } - - + + if (sPtr->flags.horizontal) { - /* paint button */ #ifndef DOUBLE_BUFFER XFillRectangle(scr->display, d, gc, @@ -326,7 +325,7 @@ paintArrow(WMScroller *sPtr, Drawable d, int part) XSetClipOrigin(scr->display, scr->clipGC, ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2); - + XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC, 0, 0, arrow->width, arrow->height, ofs + (BUTTON_SIZE - arrow->width) / 2, diff --git a/WINGs/wtext.c b/WINGs/wtext.c index 45892e62..342fae70 100644 --- a/WINGs/wtext.c +++ b/WINGs/wtext.c @@ -2026,7 +2026,7 @@ insertTextInteractively(Text *tPtr, char *text, int len) int s = tb->used - tPtr->tpos; if (!tb->blank && nlen>0) { - char *save; + char *save=NULL; if (s > 0) { save = wmalloc(s); diff --git a/WPrefs.app/Appearance.c b/WPrefs.app/Appearance.c index 22f98fd4..6bf11c6a 100644 --- a/WPrefs.app/Appearance.c +++ b/WPrefs.app/Appearance.c @@ -109,9 +109,9 @@ typedef struct _Panel { char oldTabItem; - char menuStyle; + int menuStyle; - char titleAlignment; + int titleAlignment; Pixmap preview; Pixmap previewNoText; diff --git a/WPrefs.app/Expert.c b/WPrefs.app/Expert.c index ece04a7f..974e9fdb 100644 --- a/WPrefs.app/Expert.c +++ b/WPrefs.app/Expert.c @@ -84,7 +84,7 @@ createPanel(Panel *p) WMSetButtonText(panel->swi[7], _("Smooth font edges (needs restart).")); //if (!WMHasAntialiasingSupport(WMWidgetScreen(panel->box))) - WMSetButtonEnabled(panel->swi[7], False); + WMSetButtonEnabled(panel->swi[7], True); WMRealizeWidget(panel->box); WMMapSubwidgets(panel->box); diff --git a/WPrefs.app/Focus.c b/WPrefs.app/Focus.c index 422caa21..3fbf1cda 100644 --- a/WPrefs.app/Focus.c +++ b/WPrefs.app/Focus.c @@ -219,7 +219,7 @@ createPanel(Panel *p) WMSetBoxHorizontal(box, False); panel->kfocB[0] = WMCreateRadioButton(box); - WMSetButtonText(panel->kfocB[0], _("Manual: Click on the window to set "\ + WMSetButtonText(panel->kfocB[0], _("Manual: Click on the window to set "\ "keyboard input focus")); WMAddBoxSubview(box, WMWidgetView(panel->kfocB[0]), True, True, 20, 0, 0); @@ -243,13 +243,13 @@ createPanel(Panel *p) WMSetFrameTitle(panel->cfocF, _("Install colormap in the window...")); panel->manB = WMCreateRadioButton(panel->cfocF); - WMResizeWidget(panel->manB, 220, 20); - WMMoveWidget(panel->manB, 15, 18); + WMResizeWidget(panel->manB, 225, 20); + WMMoveWidget(panel->manB, 10, 18); WMSetButtonText(panel->manB, _("...that has the input focus.")); panel->autB = WMCreateRadioButton(panel->cfocF); - WMResizeWidget(panel->autB, 220, 20); - WMMoveWidget(panel->autB, 15, 40); + WMResizeWidget(panel->autB, 225, 20); + WMMoveWidget(panel->autB, 10, 43); WMSetButtonText(panel->autB, _("...that is under the mouse pointer.")); WMGroupButtons(panel->manB, panel->autB); @@ -331,15 +331,15 @@ createPanel(Panel *p) WMMoveWidget(panel->optF, 265, 95); panel->ignB = WMCreateSwitchButton(panel->optF); - WMResizeWidget(panel->ignB, 210, 50); - WMMoveWidget(panel->ignB, 15, 10); - WMSetButtonText(panel->ignB, _("Do not let applications receive\n" - "the click used to focus windows.")); + WMResizeWidget(panel->ignB, 225, 50); + WMMoveWidget(panel->ignB, 10, 10); + WMSetButtonText(panel->ignB, _("Do not let applications receive " + "the click used to focus windows.")); panel->newB = WMCreateSwitchButton(panel->optF); - WMResizeWidget(panel->newB, 210, 35); - WMMoveWidget(panel->newB, 15, 70); - WMSetButtonText(panel->newB, _("Automatically focus new\nwindows.")); + WMResizeWidget(panel->newB, 225, 35); + WMMoveWidget(panel->newB, 10, 70); + WMSetButtonText(panel->newB, _("Automatically focus new windows.")); WMMapSubwidgets(panel->optF); diff --git a/WPrefs.app/Font.c b/WPrefs.app/Font.c index 4d5c8b28..a6d01074 100644 --- a/WPrefs.app/Font.c +++ b/WPrefs.app/Font.c @@ -23,7 +23,7 @@ #include "WPrefs.h" #include - +#include typedef struct _Panel { WMBox *box; @@ -358,7 +358,7 @@ paintItems(WMScreen *scr, Drawable d, WMColor *color, WMFont *font, int l = strlen(text); int x = previewPositions[part].pos.x; int y = previewPositions[part].pos.y; - int w = previewPositions[part].size.width; + //int w = previewPositions[part].size.width; int h = previewPositions[part].size.height/4; int i; for( i = 0; i < 4 ; i++) { @@ -443,7 +443,7 @@ dumpRImage(char *path, RImage *image) } } -static int +/*static int isPixmap(WMPropList *prop) { WMPropList *p; @@ -455,7 +455,7 @@ isPixmap(WMPropList *prop) return 1; else return 0; -} +}*/ static Pixmap renderTexture(WMScreen *scr, WMPropList *texture, int width, int height, @@ -669,7 +669,7 @@ renderMenu(_Panel *panel, WMPropList *texture, int width, int iheight) WMScreen *scr = WMWidgetScreen(panel->parent); Display *dpy = WMScreenDisplay(scr); Pixmap pix, tmp; - RContext *rc = WMScreenRContext(scr); + //RContext *rc = WMScreenRContext(scr); GC gc = XCreateGC(dpy, WMWidgetXID(panel->parent), 0, NULL); int i; @@ -835,7 +835,7 @@ paintPreviewBox(Panel *panel, int elements) { WMScreen *scr = WMWidgetScreen(panel->parent); Display *dpy = WMScreenDisplay(scr); - int refresh = 0; + //int refresh = 0; GC gc; WMColor *black = WMBlackColor(scr); Pixmap mitem; @@ -926,7 +926,7 @@ static void paintTextField(void *data, int section) { _Panel *panel = (_Panel*)data; - char *sample = NULL; + //char *sample = NULL; int encoding; encoding = WMGetPopUpButtonSelectedItem(panel->langP); WMSetTextFieldFont(panel->fontT, getFontForPreview(panel, section)); @@ -1072,7 +1072,7 @@ refillFontSetList(void *data) char *encoding = getFontEncoding(panel); int section = WMGetPopUpButtonSelectedItem(panel->fontSel); int i; - int pos; + //int pos; WMClearList(panel->fsetLs); if(!encoding) { array = getCurrentFontProp(panel, section); @@ -1259,7 +1259,7 @@ static void changeLanguageAction(WMWidget *w, void *data) { Panel *panel = (Panel*)data; - WMScreen *scr = WMWidgetScreen(panel->box); + //WMScreen *scr = WMWidgetScreen(panel->box); int section; section = WMGetPopUpButtonSelectedItem(w); @@ -1314,7 +1314,7 @@ static char* getFontSampleString(void *data) { _Panel *panel = (_Panel*)data; - WMScreen *scr = WMWidgetScreen(panel->box); + //WMScreen *scr = WMWidgetScreen(panel->box); WMMenuItem *mi; WMPropList *pl; int section; @@ -1336,7 +1336,7 @@ static char* getFontEncoding(void *data) { _Panel *panel = (_Panel*)data; - WMScreen *scr = WMWidgetScreen(panel->box); + //WMScreen *scr = WMWidgetScreen(panel->box); WMMenuItem *mi; WMPropList *pl; int section; @@ -1358,7 +1358,7 @@ static Bool isEncodingMultiByte(void *data) { _Panel *panel = (_Panel*)data; - WMScreen *scr = WMWidgetScreen(panel->box); + //WMScreen *scr = WMWidgetScreen(panel->box); WMMenuItem *mi; WMPropList *pl; int section; @@ -1473,26 +1473,20 @@ getDefaultSystemFont(void *data, int element) { _Panel *panel = (_Panel*)data; WMScreen *scr = WMWidgetScreen(panel->box); - switch(element) { - case 0: - return WMBoldSystemFontOfSize(scr, 12); - break; - case 1: - return WMBoldSystemFontOfSize(scr, 24); - break; - case 2: - return WMBoldSystemFontOfSize(scr, 12); - break; - case 3: - return WMSystemFontOfSize(scr, 12); - break; - case 4: - return WMSystemFontOfSize(scr, 8); - break; - case 5: - return WMSystemFontOfSize(scr, 8); - break; - } + + switch(element) { + case 0: + case 2: + return WMBoldSystemFontOfSize(scr, 12); + case 1: + return WMBoldSystemFontOfSize(scr, 24); + case 4: + case 5: + return WMSystemFontOfSize(scr, 8); + case 3: + default: + return WMSystemFontOfSize(scr, 12); + } } static void @@ -1515,7 +1509,7 @@ static void toggleAA(WMWidget *w, void *data) { _Panel *panel = (_Panel*)data; - int section; + //int section; if(panel->AntialiasedText) panel->AntialiasedText = False; else @@ -1622,7 +1616,7 @@ addButtonAction(WMWidget *w, void *data) array = getDefaultFontProp(panel, encoding, section); WMHideFontPanel(panel->fontPanel); - chosenFont = WMGetFontPanelFontName(panel->fontPanel); + chosenFont = WMGetFontName(WMGetFontPanelFont(panel->fontPanel)); string = WMCreatePLString(chosenFont); pos = WMGetListSelectedItemRow(panel->fsetLs); WMInsertListItem(panel->fsetLs, pos+1, chosenFont); @@ -1651,7 +1645,7 @@ changeButtonAction(WMWidget *w, void *data) WMHideFontPanel(panel->fontPanel); - chosenFont = WMGetFontPanelFontName(panel->fontPanel); + chosenFont = WMGetFontName(WMGetFontPanelFont(panel->fontPanel)); string = WMCreatePLString(chosenFont); pos = WMGetListSelectedItemRow(panel->fsetLs); @@ -1720,7 +1714,7 @@ removeButtonClick(WMWidget *w, void *data) static void showData(_Panel *panel) { - WMScreen *scr = WMWidgetScreen(panel->parent); + //WMScreen *scr = WMWidgetScreen(panel->parent); char *str; int i; diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index 76e3eb27..fadee5da 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -112,6 +112,12 @@ static char *keyOptions[] = { "WindowShortcut9Key", "WindowShortcut10Key", "ScreenSwitchKey", +#ifdef VIRTUAL_DESKTOP + "VirtualEdgeLeftKey", + "VirtualEdgeRightKey", + "VirtualEdgeUpKey", + "VirtualEdgeDownKey", +#endif "ClipRaiseKey", "ClipLowerKey", #ifndef XKB_MODELOCK @@ -326,7 +332,7 @@ captureClick(WMWidget *w, void *data) } panel->capturing = 0; WMSetButtonText(w, _("Capture")); - WMSetLabelText(panel->instructionsL, _("Click Capture to interactively define the shortcut key.")); + WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key.")); XUngrabKeyboard(dpy, CurrentTime); } @@ -537,6 +543,12 @@ createPanel(Panel *p) WMAddListItem(panel->actLs, _("Shortcut for window 9")); WMAddListItem(panel->actLs, _("Shortcut for window 10")); WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor")); +#ifdef VIRTUAL_DESKTOP + WMAddListItem(panel->actLs, _("Move VirtualDesktop to next left edge")); + WMAddListItem(panel->actLs, _("Move VirtualDesktop to next right edge")); + WMAddListItem(panel->actLs, _("Move VirtualDesktop to next top edge")); + WMAddListItem(panel->actLs, _("Move VirtualDesktop to next bottom edge")); +#endif WMAddListItem(panel->actLs, _("Raise Clip")); WMAddListItem(panel->actLs, _("Lower Clip")); WMAddListItem(panel->actLs, _("Raise/Lower Clip")); @@ -580,7 +592,7 @@ createPanel(Panel *p) WMMoveWidget(panel->instructionsL, 15, 140); WMSetLabelTextAlignment(panel->instructionsL, WACenter); WMSetLabelWraps(panel->instructionsL, True); - WMSetLabelText(panel->instructionsL, _("Click Capture to interactively define the shortcut key.")); + WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key.")); WMMapSubwidgets(panel->shoF); diff --git a/WPrefs.app/Makefile.am b/WPrefs.app/Makefile.am index e2e65d77..917ee3fa 100644 --- a/WPrefs.app/Makefile.am +++ b/WPrefs.app/Makefile.am @@ -42,7 +42,9 @@ WPrefs_SOURCES = \ imagebrowser.h \ xmodifier.c -AM_CPPFLAGS = @CPPFLAGS@ -DLOCALEDIR=\"$(NLSDIR)\" +AM_CPPFLAGS = -DLOCALEDIR=\"$(NLSDIR)\" + +AM_CFLAGS = -fno-strict-aliasing INCLUDES = -I$(top_srcdir)/wrlib -I$(top_srcdir)/WINGs @HEADER_SEARCH_PATH@ diff --git a/WPrefs.app/WPrefs.c b/WPrefs.app/WPrefs.c index f25853eb..fa06a73e 100644 --- a/WPrefs.app/WPrefs.c +++ b/WPrefs.app/WPrefs.c @@ -845,10 +845,10 @@ loadConfigurations(WMScreen *scr, WMWindow *mainw) } if (!db) { - db = WMCreatePLDictionary(NULL, NULL, NULL); + db = WMCreatePLDictionary(NULL, NULL); } if (!gdb) { - gdb = WMCreatePLDictionary(NULL, NULL, NULL); + gdb = WMCreatePLDictionary(NULL, NULL); } GlobalDB = gdb; diff --git a/WPrefs.app/WindowHandling.c b/WPrefs.app/WindowHandling.c index 2f802873..7965a015 100644 --- a/WPrefs.app/WindowHandling.c +++ b/WPrefs.app/WindowHandling.c @@ -397,18 +397,16 @@ createPanel(Panel *p) WMMoveWidget(panel->resL, 95, 20); panel->resaB = WMCreateRadioButton(panel->resF); - WMMoveWidget(panel->resaB, 130, 14); - WMResizeWidget(panel->resaB, 70, 26); + WMMoveWidget(panel->resaB, 130, 15); + WMResizeWidget(panel->resaB, 70, 25); WMSetButtonText(panel->resaB, _("Resist")); panel->resrB = WMCreateRadioButton(panel->resF); - WMMoveWidget(panel->resrB, 200, 12); - WMResizeWidget(panel->resrB, 65, 30); + WMMoveWidget(panel->resrB, 200, 15); + WMResizeWidget(panel->resrB, 70, 25); WMSetButtonText(panel->resrB, _("Attract")); WMGroupButtons(panel->resrB, panel->resaB); - - WMMapSubwidgets(panel->resF); /**************** Transients on Parent Workspace ****************/ @@ -420,7 +418,7 @@ createPanel(Panel *p) panel->tranB = WMCreateSwitchButton(panel->tranF); WMMoveWidget(panel->tranB, 10, 5); WMResizeWidget(panel->tranB, 250, 30); - WMSetButtonText(panel->tranB, _("Open dialogs in same workspace\nas their owners")); + WMSetButtonText(panel->tranB, _("Open dialogs in the same workspace\nas their owners")); WMMapSubwidgets(panel->tranF); diff --git a/WPrefs.app/Workspace.c b/WPrefs.app/Workspace.c index 5de76b40..2c1c9421 100644 --- a/WPrefs.app/Workspace.c +++ b/WPrefs.app/Workspace.c @@ -180,7 +180,7 @@ createPanel(Panel *p) WMResizeWidget(panel->cyclB, 280, 34); WMMoveWidget(panel->cyclB, 75, 30); WMSetButtonText(panel->cyclB, - _("wrap to the first workspace after the\nlast workspace.")); + _("Wrap to the first workspace from the last workspace.")); panel->cyclL = WMCreateLabel(panel->navF); WMResizeWidget(panel->cyclL, 60, 60); @@ -202,7 +202,7 @@ createPanel(Panel *p) WMResizeWidget(panel->linkB, 280, 34); WMMoveWidget(panel->linkB, 75, 75); WMSetButtonText(panel->linkB, - _("switch workspaces while dragging windows.")); + _("Switch workspaces while dragging windows.")); panel->linkL = WMCreateLabel(panel->navF); WMResizeWidget(panel->linkL, 60, 40); @@ -224,7 +224,7 @@ createPanel(Panel *p) WMResizeWidget(panel->newB, 280, 34); WMMoveWidget(panel->newB, 75, 120); WMSetButtonText(panel->newB, - _("automatically create new workspaces.")); + _("Automatically create new workspaces.")); panel->newL = WMCreateLabel(panel->navF); WMResizeWidget(panel->newL, 60, 20); diff --git a/WindowMaker/Defaults/WMWindowAttributes.in b/WindowMaker/Defaults/WMWindowAttributes.in index a6226750..aad41fa2 100644 --- a/WindowMaker/Defaults/WMWindowAttributes.in +++ b/WindowMaker/Defaults/WMWindowAttributes.in @@ -75,6 +75,9 @@ DontSaveSession = Yes; Unfocusable = Yes; }; + kio_uiserver = {NoAppIcon = Yes;}; + kcmshell = {NoAppIcon = Yes;}; + kded = {NoAppIcon = Yes;}; "." = {NoAppIcon = Yes;}; "*" = {Icon = defaultAppIcon.#extension#;SharedAppIcon = Yes;}; } diff --git a/acinclude.m4 b/acinclude.m4 index f0f906b1..ee22091b 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -25,6 +25,42 @@ CPPFLAGS="$CPPFLAGS_old" dnl +dnl WM_CHECK_XFT_VERSION(MIN_VERSION, [ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]) +dnl +dnl # $XFTFLAGS should be defined before calling this macro, +dnl # else it will not be able to find Xft.h +dnl +AC_DEFUN(WM_CHECK_XFT_VERSION, +[ +CPPFLAGS_old="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $XFTFLAGS $inc_search_path" +xft_major_version=`echo $1 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` +xft_minor_version=`echo $1 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` +xft_micro_version=`echo $1 | sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` +AC_MSG_CHECKING([whether libXft is at least version $1]) +AC_CACHE_VAL(ac_cv_lib_xft_version_ok, +[AC_TRY_LINK( +[/* Test version of libXft we have */ +#include + +#if !defined(XFT_VERSION) || XFT_VERSION < $xft_major_version*10000 + $xft_minor_version*100 + $xft_micro_version +#error libXft on this system is too old. Consider upgrading to at least $1 +#endif +], [], +eval "ac_cv_lib_xft_version_ok=yes", +eval "ac_cv_lib_xft_version_ok=no")]) +if eval "test \"`echo '$ac_cv_lib_xft_version_ok'`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) +else + AC_MSG_RESULT(no) + ifelse([$3], , , [$3]) +fi +CPPFLAGS="$CPPFLAGS_old" +]) + + +dnl dnl WM_CHECK_REDCRAP_BUGS(prefix,bindir,libdir) dnl AC_DEFUN(WM_CHECK_REDCRAP_BUGS, diff --git a/configure.ac b/configure.ac index eabd927f..adfbd739 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ AC_INIT(src/WindowMaker.h) -AM_INIT_AUTOMAKE(WindowMaker, 0.90.0) +AM_INIT_AUTOMAKE(WindowMaker, 0.85.0) AC_PROG_LIBTOOL @@ -224,7 +224,7 @@ if test "$ac_cv_prog_gcc" = yes; then AC_CACHE_CHECK(whether gcc supports MMX(tm) inline asm, ac_cv_c_inline_mmx, - [AC_TRY_LINK(,[asm ("movq %mm0, %mm1");], + [AC_TRY_LINK(,[__asm__ ("movq %mm0, %mm1");], ac_cv_c_inline_mmx=yes, ac_cv_c_inline_mmx=no)]) @@ -295,7 +295,7 @@ dnl ================== dnl List of supported locales dnl ------------------------- -supported_locales="be bg ca cs da de el es et fi fr gl hr hu it ja ko ms nl no pl pt ro ru sk sv tr zh_CN zh_TW.Big5" +supported_locales="be bg bs ca cs da de el es et fi fr gl hr hu it ja ko ms nl no pl pt ro ru sk sv tr zh_CN zh_TW.Big5" supported_wprefs_locales="bg ca cs de es et fi fr hr hu it ja ko pt ru sk zh_CN zh_TW.Big5" supported_wings_locales="bg ca cs de fr sk" @@ -376,6 +376,12 @@ AC_SUBST(supported_locales) dnl Support for various hint things dnl =============================== +gnome_on="no" +kde_on="no" +openlook_on="no" +netwm_on="no" +vdesktop_on="no" + AC_ARG_ENABLE(gnome, [ --enable-gnome enable stuff needed for GNOME ], @@ -401,6 +407,22 @@ AC_ARG_ENABLE(openlook, fi]) +AC_ARG_ENABLE(netwm, + [ --enable-netwm enable support for FreeDesktop hints ], + [if test x$enableval = xyes; then + AC_DEFINE(NETWM_HINTS, 1, [define if you want NETWM hints support]) + netwm_on=yes + fi]) + + +AC_ARG_ENABLE(vdesktop, + [ --enable-vdesktop enable virtual desktop], + [if test x$enableval = xyes; then + AC_DEFINE(VIRTUAL_DESKTOP, 1, [define if you want virtual desktop support]) + vdesktop_on=yes + fi]) + + dnl dnl Disable some stuff that are duplicated in kde dnl --------------------------------------------- @@ -519,35 +541,54 @@ fi dnl Xft antialiased font support dnl ============================ + xft=yes XFTLIBS="" -AC_ARG_ENABLE(xft, -[ --disable-xft disable Xft antialiased font support], - xft=$enableval, xft=yes) - -if test "$xft" = yes; then - if test "x$PKGCONFIG" != x -a "`$PKGCONFIG xft; echo $?`" = 0; then - XFTCONFIG="$PKGCONFIG xft" - pkgconfig_xft=yes - else - AC_CHECK_PROG(XFTCONFIG, xft-config, xft-config) - fi - AC_MSG_CHECKING([for the Xft2 library]) - if test "x$XFTCONFIG" != x; then - XFTLIBS=`$XFTCONFIG --libs` - XFTFLAGS=`$XFTCONFIG --cflags` - AC_MSG_RESULT([found]) - else - xft=no - AC_MSG_RESULT([not found]) - fi - if test "$xft" = yes; then - AC_SUBST(XFTFLAGS) - AC_SUBST(XFTLIBS) - AC_DEFINE(XFT, 1, [define if you want support for antialiased fonts (set by configure)]) - fi + +if test "x$PKGCONFIG" != x -a "`$PKGCONFIG xft; echo $?`" = 0; then + XFTCONFIG="$PKGCONFIG xft" + pkgconfig_xft=yes +else + AC_CHECK_PROG(XFTCONFIG, xft-config, xft-config) +fi + +AC_MSG_CHECKING([for the Xft2 library]) + +if test "x$XFTCONFIG" != x; then + XFTLIBS=`$XFTCONFIG --libs` + XFTFLAGS=`$XFTCONFIG --cflags` + AC_MSG_RESULT([found]) +else + AC_MSG_RESULT([not found]) + echo + echo "ERROR!!! libXft2 is not installed or could not be found." + echo " Xft2 is a requirement for building Window Maker." + echo " Please install it (along with fontconfig) before continuing." + echo + exit 1 fi +minXFT="2.1.2" +goodxft="no" + +dnl +dnl The macro below will use $XFTFLAGS (defined above) to find Xft.h +dnl +WM_CHECK_XFT_VERSION($minXFT, goodxft=yes, goodxft=no) + +if test "$goodxft" = no; then + echo + echo "ERROR!!! libXft on this system is an old version." + echo " Please consider upgrading to at least version ${minXFT}." + echo + exit 1 +fi + +AC_SUBST(XFTFLAGS) +AC_SUBST(XFTLIBS) +AC_DEFINE(XFT, 1, [define if you want support for antialiased fonts (set by configure)]) + + dnl XINERAMA support dnl ================ xinerama=no @@ -845,14 +886,14 @@ AC_ARG_WITH(appspath, [ --with-appspath=PATH specify the directory for GNUstep applications], appspath=$withval ) if test "x$appspath" = "x"; then - gnustepdir='$(prefix)/GNUstep' + gnustepdir='${prefix}/GNUstep' if test "x$GNUSTEP_LOCAL_ROOT" != "x" ; then gnustepdir=`echo "$GNUSTEP_LOCAL_ROOT" | sed -e "s|^${prefix}|prefix|"` gnustepdir=`echo $gnustepdir | sed -e 's|^prefix|${prefix}|'` fi - with_appspath=$gnustepdir/Apps + with_appspath=$gnustepdir/Applications fi wprefsdir=$with_appspath/WPrefs.app @@ -1075,29 +1116,48 @@ dnl ========================== supported_gfx="$supported_gfx builtin-PPM" if test "x$MOFILES" = "x"; then - mof=none + mof=None else mof=`echo $MOFILES` fi if test "x$MOFILES" = "x"; then - languages=none + languages=None else languages=`echo $MOFILES | sed 's/.mo//g'` fi +extrasupport='' +if test "$openlook_on" = "yes"; then + extrasupport="OpenLook $extrasupport" +fi +if test "$gnome_on" = "yes"; then + extrasupport="Gnome $extrasupport" +fi +if test "$kde_on" = "yes"; then + extrasupport="KDE $extrasupport" +fi +if test "$netwm_on" = "yes"; then + extrasupport="NetWM $extrasupport" +fi + +if test "x$extrasupport" = "x"; then + extrasupport="None" +fi echo echo "Window Maker was configured as follows:" echo echo "Installation path prefix : $prefix" echo "Installation path for binaries : $_bindir" -echo "Installation path for WPrefs.app : $wprefsdir" | sed -e 's|\$(prefix)|'"$prefix|" +echo "Installation path for WPrefs.app : $with_appspath" | sed -e 's|\${prefix}|'"$prefix|" echo "Supported graphic format libraries : $supported_gfx" -echo "Antialiased text support for WINGs : $xft" -echo "Xinerama extension support : $xinerama" echo "Use assembly routines for wrlib : $asm_support" echo "Use inline MMX(tm) x86 assembly : $mmx_support" +echo "Antialiased text support in WINGs : $xft" +echo "Xinerama extension support : $xinerama" +echo "Virtual desktop support : $vdesktop_on" +echo "Additionally supported environments : $extrasupport" echo "Translated message files to install : $mof" dnl echo "Supported languages beside English : $languages" if test "x$MOFILES" != "x"; then diff --git a/src/Makefile.am b/src/Makefile.am index a89a5c02..3476125a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -96,6 +96,8 @@ wmaker_SOURCES = \ winmenu.c \ winspector.h \ winspector.c \ + wmspec.h \ + wmspec.c \ workspace.c \ workspace.h \ wsound.c \ @@ -104,7 +106,9 @@ wmaker_SOURCES = \ text.h -AM_CPPFLAGS = @CPPFLAGS@ $(DFLAGS) -DLOCALEDIR=\"$(NLSDIR)\" +AM_CPPFLAGS = $(DFLAGS) -DLOCALEDIR=\"$(NLSDIR)\" + +AM_CFLAGS = -fno-strict-aliasing INCLUDES = \ diff --git a/src/WindowMaker.h b/src/WindowMaker.h index e8c2bf59..711e133c 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -70,6 +70,7 @@ enum { WMSubmenuLevel = 6, WMMainMenuLevel = 20, WMStatusLevel = 21, + WMFullscreenLevel = 50, WMModalLevel = 100, WMPopUpLevel = 101, WMScreensaverLevel = 1000, @@ -118,40 +119,41 @@ typedef enum { #define WBUT_ICONIFY 2 #define WBUT_KILL 3 #ifdef XKB_BUTTON_HINT -#define WBUT_XKBGROUP1 4 -#define WBUT_XKBGROUP2 5 -#define WBUT_XKBGROUP3 6 -#define WBUT_XKBGROUP4 7 +#define WBUT_XKBGROUP1 4 +#define WBUT_XKBGROUP2 5 +#define WBUT_XKBGROUP3 6 +#define WBUT_XKBGROUP4 7 #define PRED_BPIXMAPS 8 /* reserved for 4 groups */ #else #define PRED_BPIXMAPS 4 /* count of WBUT icons */ #endif /* XKB_BUTTON_HINT */ /* cursors */ -#define WCUR_DEFAULT 0 -#define WCUR_NORMAL 0 -#define WCUR_MOVE 1 -#define WCUR_RESIZE 2 +#define WCUR_DEFAULT 0 +#define WCUR_NORMAL 0 +#define WCUR_MOVE 1 +#define WCUR_RESIZE 2 #define WCUR_TOPLEFTRESIZE 3 #define WCUR_TOPRIGHTRESIZE 4 #define WCUR_BOTTOMLEFTRESIZE 5 #define WCUR_BOTTOMRIGHTRESIZE 6 -#define WCUR_VERTICALRESIZE 7 -#define WCUR_HORIZONRESIZE 8 -#define WCUR_WAIT 9 -#define WCUR_ARROW 10 -#define WCUR_QUESTION 11 -#define WCUR_TEXT 12 -#define WCUR_SELECT 13 -#define WCUR_ROOT 14 -#define WCUR_LAST 15 +#define WCUR_VERTICALRESIZE 7 +#define WCUR_HORIZONRESIZE 8 +#define WCUR_WAIT 9 +#define WCUR_ARROW 10 +#define WCUR_QUESTION 11 +#define WCUR_TEXT 12 +#define WCUR_SELECT 13 +#define WCUR_ROOT 14 +#define WCUR_EMPTY 15 +#define WCUR_LAST 16 /* geometry displays */ -#define WDIS_NEW 0 /* new style */ -#define WDIS_CENTER 1 /* center of screen */ -#define WDIS_TOPLEFT 2 /* top left corner of screen */ -#define WDIS_FRAME_CENTER 3 /* center of the frame */ -#define WDIS_NONE 4 +#define WDIS_NEW 0 /* new style */ +#define WDIS_CENTER 1 /* center of screen */ +#define WDIS_TOPLEFT 2 /* top left corner of screen */ +#define WDIS_FRAME_CENTER 3 /* center of the frame */ +#define WDIS_NONE 4 /* keyboard input focus mode */ #define WKF_CLICK 0 @@ -181,10 +183,10 @@ typedef enum { #define WIS_RANDOM 4 /* secret */ /* switchmenu actions */ -#define ACTION_ADD 0 -#define ACTION_REMOVE 1 -#define ACTION_CHANGE 2 -#define ACTION_CHANGE_WORKSPACE 3 +#define ACTION_ADD 0 +#define ACTION_REMOVE 1 +#define ACTION_CHANGE 2 +#define ACTION_CHANGE_WORKSPACE 3 #define ACTION_CHANGE_STATE 4 @@ -202,8 +204,8 @@ typedef enum { #define WS_PFOCUSED 2 /* clip title colors */ -#define CLIP_NORMAL 0 -#define CLIP_COLLAPSED 1 +#define CLIP_NORMAL 0 +#define CLIP_COLLAPSED 1 /* icon yard position */ @@ -420,8 +422,8 @@ typedef struct WPreferences { unsigned int vedge_bordersize; unsigned int vedge_hscrollspeed; unsigned int vedge_vscrollspeed; - unsigned int vedge_maxheight; - unsigned int vedge_maxwidth; + unsigned int vedge_resistance; + unsigned int vedge_attraction; #endif char ws_cycle; /* Cycle existing workspaces */ diff --git a/src/actions.c b/src/actions.c index 47f42881..c218f17a 100644 --- a/src/actions.c +++ b/src/actions.c @@ -69,6 +69,8 @@ extern WPreferences wPreferences; extern Atom _XA_WM_TAKE_FOCUS; +extern void ProcessPendingEvents(); + /******* Local Variables *******/ static struct { @@ -85,37 +87,6 @@ static struct { #define SHADE_DELAY shadePars[(int)wPreferences.shade_speed].delay -static int ignoreTimestamp=0; - - -#ifdef ANIMATIONS -static void -processEvents(int event_count) -{ - XEvent event; - - /* - * This is a hack. When animations are enabled, processing of - * events ocurred during a animation are delayed until it's end. - * Calls that consider the TimeStamp, like XSetInputFocus(), will - * fail because the TimeStamp is too old. Then, for example, if - * the user changes window focus while a miniaturize animation is - * in course, the window will not get focus properly after the end - * of the animation. This tries to workaround it by passing CurrentTime - * as the TimeStamp for XSetInputFocus() for all events ocurred during - * the animation. - */ - ignoreTimestamp=1; - while (XPending(dpy) && event_count--) { - WMNextEvent(dpy, &event); - WMHandleEvent(&event); - } - ignoreTimestamp=0; -} -#endif /* ANIMATIONS */ - - - /* *---------------------------------------------------------------------- * wSetFocusTo-- @@ -139,33 +110,21 @@ wSetFocusTo(WScreen *scr, WWindow *wwin) int timestamp=LastTimestamp; WApplication *oapp=NULL, *napp=NULL; int wasfocused; + + if (scr->flags.ignore_focus_events || LastFocusChange > timestamp) + return; if (!old_scr) old_scr=scr; old_focused=old_scr->focused_window; - /* - * Safeguard: make sure the timestamp is monotonically increasing - * (very unlikely that this will be needed, still a safeguard) - */ - if (timestamp <= LastFocusChange) - timestamp = LastFocusChange + 1; - LastFocusChange = timestamp; - /* - * This is a hack, because XSetInputFocus() should have a proper - * timestamp instead of CurrentTime but it seems that some times - * clients will not receive focus properly that way. - */ - if (ignoreTimestamp) - timestamp = CurrentTime; - if (old_focused) oapp = wApplicationOf(old_focused->main_window); if (wwin == NULL) { - XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp); + XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); if (old_focused) { wWindowUnfocus(old_focused); } @@ -199,12 +158,12 @@ wSetFocusTo(WScreen *scr, WWindow *wwin) /* set input focus */ switch (wwin->focus_mode) { case WFM_NO_INPUT: - XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp); + XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); break; case WFM_PASSIVE: case WFM_LOCALLY_ACTIVE: - XSetInputFocus(dpy, wwin->client_win, RevertToParent, timestamp); + XSetInputFocus(dpy, wwin->client_win, RevertToParent, CurrentTime); break; case WFM_GLOBALLY_ACTIVE: @@ -216,7 +175,7 @@ wSetFocusTo(WScreen *scr, WWindow *wwin) } XSync(dpy, False); } else { - XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, timestamp); + XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime); } if (WFLAGP(wwin, no_focusable)) return; @@ -333,9 +292,8 @@ wShadeWindow(WWindow *wwin) #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup) { - /* Look at processEvents() for reason of this code. */ - XSync(dpy, 0); - processEvents(XPending(dpy)); + /* Catch up with events not processed while animation was running */ + ProcessPendingEvents(); } #endif } @@ -419,7 +377,7 @@ wMaximizeWindow(WWindow *wwin, int directions) int changed_h, changed_v, shrink_h, shrink_v; WArea usableArea, totalArea; - if (WFLAGP(wwin, no_resizable)) + if (!IS_RESIZABLE(wwin)) return; totalArea.x1 = 0; @@ -550,6 +508,65 @@ wUnmaximizeWindow(WWindow *wwin) wSoundPlay(WSOUND_UNMAXIMIZE); } + +void +wFullscreenWindow(WWindow *wwin) +{ + int head; + WMRect rect; + + if (wwin->flags.fullscreen) + return; + + wwin->flags.fullscreen = True; + + wWindowConfigureBorders(wwin); + + ChangeStackingLevel(wwin->frame->core, WMFullscreenLevel); + + wwin->bfs_geometry.x = wwin->frame_x; + wwin->bfs_geometry.y = wwin->frame_y; + wwin->bfs_geometry.width = wwin->frame->core->width; + wwin->bfs_geometry.height = wwin->frame->core->height; + + head = wGetHeadForWindow(wwin); + rect = wGetRectForHead(wwin->screen_ptr, head); + wWindowConfigure(wwin, rect.pos.x, rect.pos.y, + rect.size.width, rect.size.height); + + WMPostNotificationName(WMNChangedState, wwin, "fullscreen"); +} + + +void +wUnfullscreenWindow(WWindow *wwin) +{ + if (!wwin->flags.fullscreen) + return; + + wwin->flags.fullscreen = False; + + if (wwin->frame->core->stacking->window_level == WMFullscreenLevel) { + if (WFLAGP(wwin, sunken)) { + ChangeStackingLevel(wwin->frame->core, WMSunkenLevel); + } else if (WFLAGP(wwin, floating)) { + ChangeStackingLevel(wwin->frame->core, WMFloatingLevel); + } else { + ChangeStackingLevel(wwin->frame->core, WMNormalLevel); + } + } + + wWindowConfigure(wwin, wwin->bfs_geometry.x, wwin->bfs_geometry.y, + wwin->bfs_geometry.width, wwin->bfs_geometry.height); + + wWindowConfigureBorders(wwin); + // seems unnecessary, but also harmless (doesn't generate flicker) -Dan + wFrameWindowPaint(wwin->frame); + + WMPostNotificationName(WMNChangedState, wwin, "fullscreen"); +} + + #ifdef ANIMATIONS static void animateResizeFlip(WScreen *scr, int x, int y, int w, int h, @@ -943,7 +960,11 @@ wIconifyWindow(WWindow *wwin) GrabModeAsync, None, None, CurrentTime); } - if (!wPreferences.disable_miniwindows) { + if (!wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) { if (!wwin->flags.icon_moved) { PlaceIcon(wwin->screen_ptr, &wwin->icon_x, &wwin->icon_y, wGetHeadForWindow(wwin)); } @@ -968,7 +989,11 @@ wIconifyWindow(WWindow *wwin) * something before the animation starts (and the server is grabbed) */ XSync(dpy, 0); - if (wPreferences.disable_miniwindows) + if (wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + || wwin->flags.net_handle_icon +#endif + ) wClientSetState(wwin, IconicState, None); else wClientSetState(wwin, IconicState, wwin->icon->icon_win); @@ -979,7 +1004,11 @@ wIconifyWindow(WWindow *wwin) && !wPreferences.no_animations) { int ix, iy, iw, ih; - if (!wPreferences.disable_miniwindows) { + if (!wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) { ix = wwin->icon_x; iy = wwin->icon_y; iw = wwin->icon->core->width; @@ -995,6 +1024,14 @@ wIconifyWindow(WWindow *wwin) ih = area.y2 - iy; } else #endif /* KWM_HINTS */ +#ifdef NETWM_HINTS + if (wwin->flags.net_handle_icon) { + ix = wwin->icon_x; + iy = wwin->icon_y; + iw = wwin->icon_w; + ih = wwin->icon_h; + } else +#endif { ix = 0; iy = 0; @@ -1011,7 +1048,11 @@ wIconifyWindow(WWindow *wwin) wwin->flags.skip_next_animation = 0; - if (!wPreferences.disable_miniwindows) { + if (!wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) { if (wwin->screen_ptr->current_workspace==wwin->frame->workspace || IS_OMNIPRESENT(wwin) || wPreferences.sticky_icons) @@ -1051,20 +1092,27 @@ wIconifyWindow(WWindow *wwin) #ifdef ANIMATIONS if (!wwin->screen_ptr->flags.startup) { + /* Catch up with events not processed while animation was running */ Window clientwin = wwin->client_win; - XSync(dpy, 0); - processEvents(XPending(dpy)); + ProcessPendingEvents(); - /* the window can disappear while doing the processEvents() */ - if (!wWindowFor(clientwin)) + /* the window can disappear while ProcessPendingEvents() runs */ + if (!wWindowFor(clientwin)) { return; + } } #endif } - - if (wwin->flags.selected && !wPreferences.disable_miniwindows) + /* maybe we want to do this regardless of net_handle_icon + * it seems to me we might break behaviour this way. + */ + if (wwin->flags.selected && !wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) wIconSelect(wwin->icon); WMPostNotificationName(WMNChangedState, wwin, "iconify"); @@ -1076,7 +1124,16 @@ wIconifyWindow(WWindow *wwin) void wDeiconifyWindow(WWindow *wwin) { - wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace); +#ifdef NETWM_HINTS + /* we're hiding for show_desktop */ + int netwm_hidden = wwin->flags.net_show_desktop && + wwin->frame->workspace!=wwin->screen_ptr->current_workspace; +#else + int netwm_hidden = False; +#endif + + if (!netwm_hidden) + wWindowChangeWorkspace(wwin, wwin->screen_ptr->current_workspace); if (!wwin->flags.miniaturized) return; @@ -1094,86 +1151,121 @@ wDeiconifyWindow(WWindow *wwin) } wwin->flags.miniaturized = 0; - if (!wwin->flags.shaded) + + if (!netwm_hidden && !wwin->flags.shaded) { wwin->flags.mapped = 1; + } - if (!wPreferences.disable_miniwindows && wwin->icon != NULL) { - if (wwin->icon->selected) - wIconSelect(wwin->icon); + if (!netwm_hidden || wPreferences.sticky_icons) { + /* maybe we want to do this regardless of net_handle_icon + * it seems to me we might break behaviour this way. + */ + if (!wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + && wwin->icon != NULL) { + if (wwin->icon->selected) + wIconSelect(wwin->icon); - XUnmapWindow(dpy, wwin->icon->core->window); + XUnmapWindow(dpy, wwin->icon->core->window); + } } - wSoundPlay(WSOUND_DEICONIFY); + if (!netwm_hidden) + wSoundPlay(WSOUND_DEICONIFY); /* if the window is in another workspace, do it silently */ + if (!netwm_hidden) { #ifdef ANIMATIONS - if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations - && !wwin->flags.skip_next_animation && wwin->icon != NULL) { - int ix, iy, iw, ih; - - if (!wPreferences.disable_miniwindows) { - ix = wwin->icon_x; - iy = wwin->icon_y; - iw = wwin->icon->core->width; - ih = wwin->icon->core->height; - } else { + if (!wwin->screen_ptr->flags.startup && !wPreferences.no_animations + && !wwin->flags.skip_next_animation && wwin->icon != NULL) { + int ix, iy, iw, ih; + + if (!wPreferences.disable_miniwindows +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) { + ix = wwin->icon_x; + iy = wwin->icon_y; + iw = wwin->icon->core->width; + ih = wwin->icon->core->height; + } else { #ifdef KWM_HINTS - WArea area; - - if (wKWMGetIconGeometry(wwin, &area)) { - ix = area.x1; - iy = area.y1; - iw = area.x2 - ix; - ih = area.y2 - iy; - } else + WArea area; + + if (wKWMGetIconGeometry(wwin, &area)) { + ix = area.x1; + iy = area.y1; + iw = area.x2 - ix; + ih = area.y2 - iy; + } else #endif /* KWM_HINTS */ - { - ix = 0; - iy = 0; - iw = wwin->screen_ptr->scr_width; - ih = wwin->screen_ptr->scr_height; - } - } - animateResize(wwin->screen_ptr, ix, iy, iw, ih, - wwin->frame_x, wwin->frame_y, - wwin->frame->core->width, wwin->frame->core->height, - False); - } +#ifdef NETWM_HINTS + if (wwin->flags.net_handle_icon) { + ix = wwin->icon_x; + iy = wwin->icon_y; + iw = wwin->icon_w; + ih = wwin->icon_h; + } else +#endif + { + ix = 0; + iy = 0; + iw = wwin->screen_ptr->scr_width; + ih = wwin->screen_ptr->scr_height; + } + } + animateResize(wwin->screen_ptr, ix, iy, iw, ih, + wwin->frame_x, wwin->frame_y, + wwin->frame->core->width, wwin->frame->core->height, + False); + } #endif /* ANIMATIONS */ - wwin->flags.skip_next_animation = 0; - XGrabServer(dpy); - if (!wwin->flags.shaded) { - XMapWindow(dpy, wwin->client_win); - } - XMapWindow(dpy, wwin->frame->core->window); - wRaiseFrame(wwin->frame->core); - if (!wwin->flags.shaded) { - wClientSetState(wwin, NormalState, None); - } - mapTransientsFor(wwin); - - if (!wPreferences.disable_miniwindows && wwin->icon != NULL) { + wwin->flags.skip_next_animation = 0; + XGrabServer(dpy); + if (!wwin->flags.shaded) { + XMapWindow(dpy, wwin->client_win); + } + XMapWindow(dpy, wwin->frame->core->window); + wRaiseFrame(wwin->frame->core); + if (!wwin->flags.shaded) { + wClientSetState(wwin, NormalState, None); + } + mapTransientsFor(wwin); + } + + if (!wPreferences.disable_miniwindows && wwin->icon != NULL +#ifdef NETWM_HINTS + && !wwin->flags.net_handle_icon +#endif + ) { RemoveFromStackList(wwin->icon->core); /* removeIconGrabs(wwin->icon);*/ wIconDestroy(wwin->icon); wwin->icon = NULL; } - XUngrabServer(dpy); - wSetFocusTo(wwin->screen_ptr, wwin); + if (!netwm_hidden) { + XUngrabServer(dpy); + + wSetFocusTo(wwin->screen_ptr, wwin); #ifdef ANIMATIONS - if (!wwin->screen_ptr->flags.startup) { - Window clientwin = wwin->client_win; + if (!wwin->screen_ptr->flags.startup) { + /* Catch up with events not processed while animation was running */ + Window clientwin = wwin->client_win; - XSync(dpy, 0); - processEvents(XPending(dpy)); + ProcessPendingEvents(); - if (!wWindowFor(clientwin)) - return; - } + /* the window can disappear while ProcessPendingEvents() runs */ + if (!wWindowFor(clientwin)) { + return; + } + } #endif + } if (wPreferences.auto_arrange_icons) { wArrangeIcons(wwin->screen_ptr, True); @@ -1182,7 +1274,8 @@ wDeiconifyWindow(WWindow *wwin) WMPostNotificationName(WMNChangedState, wwin, "iconify"); /* In case we were shaded and iconified, also unshade */ - wUnshadeWindow(wwin); + if (!netwm_hidden) + wUnshadeWindow(wwin); } @@ -1618,9 +1711,9 @@ wArrangeIcons(WScreen *scr, Bool arrangeAll) while (aicon) { if (!aicon->docked) { - /* XXX: can: icon == NULL ? */ - /* The intention here is to place the AppIcon on the head that contains most of the applications _main_ window. */ - /* printf("appicon: %x %x\n", aicon->icon->core->window, aicon->main_window); */ + /* CHECK: can icon be NULL here ? */ + /* The intention here is to place the AppIcon on the head that + * contains most of the applications _main_ window. */ head = wGetHeadForWindow(aicon->icon->owner); if (aicon->x_pos != X || aicon->y_pos != Y) { @@ -1847,7 +1940,7 @@ wSelectWindow(WWindow *wwin, Bool flag) wwin->flags.selected = 1; XSetWindowBorder(dpy, wwin->frame->core->window, scr->white_pixel); - if (WFLAGP(wwin, no_border)) { + if (!HAS_BORDER(wwin)) { XSetWindowBorderWidth(dpy, wwin->frame->core->window, FRAME_BORDER_WIDTH); } @@ -1860,7 +1953,7 @@ wSelectWindow(WWindow *wwin, Bool flag) XSetWindowBorder(dpy, wwin->frame->core->window, scr->frame_border_pixel); - if (WFLAGP(wwin, no_border)) { + if (!HAS_BORDER(wwin)) { XSetWindowBorderWidth(dpy, wwin->frame->core->window, 0); } diff --git a/src/actions.h b/src/actions.h index e3475bfe..bdabdb43 100644 --- a/src/actions.h +++ b/src/actions.h @@ -65,4 +65,8 @@ void wArrangeIcons(WScreen *scr, Bool arrangeAll); void wMakeWindowVisible(WWindow *wwin); +void wFullscreenWindow(WWindow *wwin); +void wUnfullscreenWindow(WWindow *wwin); + + #endif diff --git a/src/appicon.c b/src/appicon.c index 391dae7a..68a67527 100644 --- a/src/appicon.c +++ b/src/appicon.c @@ -407,7 +407,7 @@ setIconCallback(WMenu *menu, WMenuEntry *entry) result = wIconChooserDialog(scr, &file, icon->wm_instance, icon->wm_class); if (result && !icon->destroyed) { - if (file[0]==0) { + if (file && *file==0) { wfree(file); file = NULL; } diff --git a/src/application.c b/src/application.c index fe9b4843..9b6e1872 100644 --- a/src/application.c +++ b/src/application.c @@ -50,6 +50,8 @@ #include "dock.h" #include "wsound.h" +#include "xinerama.h" + /******** Global variables ********/ @@ -123,16 +125,14 @@ findDockIconFor(WDock *dock, Window main_window) static void extractIcon(WWindow *wwin) { - int argc; - char **argv; - - if (!XGetCommand(dpy, wwin->client_win, &argv, &argc) || argc < 1) - return; + char *progname; - wApplicationExtractDirPackIcon(wwin->screen_ptr,argv[0], - wwin->wm_instance, - wwin->wm_class); - XFreeStringList(argv); + progname = GetProgramNameForWindow(wwin->client_win); + if (progname) { + wApplicationExtractDirPackIcon(wwin->screen_ptr, progname, + wwin->wm_instance, wwin->wm_class); + wfree(progname); + } } @@ -172,7 +172,7 @@ saveIconNameFor(char *iconPath, char *wm_instance, char *wm_class) val = WMGetFromPLDictionary(adict, iconk); } else { /* no dictionary for app, so create one */ - adict = WMCreatePLDictionary(NULL, NULL, NULL); + adict = WMCreatePLDictionary(NULL, NULL); WMPutInPLDictionary(dict, key, adict); WMReleasePropList(adict); val = NULL; @@ -246,8 +246,10 @@ extractClientIcon(WAppIcon *icon) WApplication* -wApplicationCreate(WScreen *scr, Window main_window) +wApplicationCreate(WWindow *wwin) { + WScreen *scr = wwin->screen_ptr; + Window main_window = wwin->main_window; WApplication *wapp; WWindow *leader; @@ -295,6 +297,11 @@ wApplicationCreate(WScreen *scr, Window main_window) return NULL; } + wapp->main_window_desc->fake_group = wwin->fake_group; +#ifdef NETWM_HINTS + wapp->main_window_desc->net_icon_image = RRetainImage(wwin->net_icon_image); +#endif + extractIcon(wapp->main_window_desc); leader = wWindowFor(main_window); diff --git a/src/application.h b/src/application.h index f064ffee..c867298e 100644 --- a/src/application.h +++ b/src/application.h @@ -50,7 +50,7 @@ typedef struct WApplication { } WApplication; -WApplication *wApplicationCreate(WScreen *scr, Window main_window); +WApplication *wApplicationCreate(struct WWindow *wwin); void wApplicationDestroy(WApplication *wapp); WApplication *wApplicationOf(Window window); diff --git a/src/client.c b/src/client.c index 0cba6a44..96b5d90e 100644 --- a/src/client.c +++ b/src/client.c @@ -46,6 +46,9 @@ #ifdef KWM_HINTS #include "kwm.h" #endif +#ifdef NETWM_HINTS +# include "wmspec.h" +#endif /****** Global Variables ******/ @@ -239,7 +242,7 @@ wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre) /* If the window is shaded, wrong height will be set for the window */ if (xcre->value_mask & CWX) { nx = xcre->x; - if (!WFLAGP(wwin, no_border)) + if (HAS_BORDER(wwin)) nx -= FRAME_BORDER_WIDTH; } else @@ -247,7 +250,7 @@ wClientConfigure(WWindow *wwin, XConfigureRequestEvent *xcre) if (xcre->value_mask & CWY) { ny = xcre->y - ((ofs_y < 0) ? 0 : wwin->frame->top_width); - if (!WFLAGP(wwin, no_border)) + if (HAS_BORDER(wwin)) ny -= FRAME_BORDER_WIDTH; } else @@ -353,22 +356,17 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) case XA_WM_COMMAND: if (wwin->main_window!=None) { WApplication *wapp = wApplicationOf(wwin->main_window); - char **argv; - int argc; + char *command; - if (!wapp || !wapp->app_icon) + if (!wapp || !wapp->app_icon || wapp->app_icon->docked) break; - if (XGetCommand(dpy, wwin->main_window, &argv, &argc)) { - if (argc > 0 && argv != NULL) { - if (wapp->app_icon->command) - wfree(wapp->app_icon->command); - wapp->app_icon->command = wtokenjoin(argv, argc); - } - if (argv) { - XFreeStringList(argv); - } - } + command = GetCommandForWindow(wwin->main_window); + if (command) { + if (wapp->app_icon->command) + wfree(wapp->app_icon->command); + wapp->app_icon->command = command; + } } break; @@ -457,7 +455,7 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) wApplicationDestroy(wApplicationOf(wwin->main_window)); wwin->main_window = wwin->client_leader; wwin->group_id = None; - wApplicationCreate(wwin->screen_ptr, wwin->main_window); + wApplicationCreate(wwin); break; /* 1,2,4 - change leader to new value of window_group */ @@ -467,7 +465,7 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) wApplicationDestroy(wApplicationOf(wwin->main_window)); wwin->main_window = new_hints->window_group; wwin->group_id = wwin->main_window; - wApplicationCreate(wwin->screen_ptr, wwin->main_window); + wApplicationCreate(wwin); break; /* 5 - destroy application */ @@ -481,7 +479,7 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) case 6: wwin->main_window = new_hints->window_group; wwin->group_id = wwin->main_window; - wApplicationCreate(wwin->screen_ptr, wwin->main_window); + wApplicationCreate(wwin); break; /* 7 - we have a fake window group id, so just ignore anything else */ case 7: @@ -630,7 +628,7 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) else foo->main_window = None; if (foo->main_window) { - wapp = wApplicationCreate(scr, foo->main_window); + wapp = wApplicationCreate(foo); } } foo = foo->prev; @@ -665,11 +663,18 @@ wClientCheckProperty(WWindow *wwin, XPropertyEvent *event) XFree(attr); } else { +#if defined(KWM_HINTS) || defined(NETWM_HINTS) + Bool done = False; +#endif #ifdef KWM_HINTS - Bool done; - - done = wKWMCheckClientHintChange(wwin, event); + if (!done) + done = wKWMCheckClientHintChange(wwin, event); #endif /* KWM_HINTS */ +#ifdef NETWM_HINTS + if (!done) { + done = wNETWMCheckClientHintChange(wwin, event); + } +#endif } } } diff --git a/src/cycling.c b/src/cycling.c index 8e0c98d2..e5ace829 100644 --- a/src/cycling.c +++ b/src/cycling.c @@ -198,7 +198,9 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) if (hasModifier) { keymap = XGetModifierMapping(dpy); - +#ifdef DEBUG + printf("Grabbing keyboard\n"); +#endif XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime); } @@ -223,11 +225,6 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) wWindowFocus(newFocused, scr->focused_window); oldFocused = newFocused; - if (hasModifier) - done = False; - else - done = True; - #if 0 if (wPreferences.popup_switchmenu && (!scr->switch_menu || !scr->switch_menu->flags.mapped)) { @@ -236,8 +233,9 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) openedSwitchMenu = True; } #endif - while (!done) { - WMMaskEvent(dpy,KeyPressMask|KeyReleaseMask|ExposureMask, &ev); + + while (hasModifier && !done) { + WMMaskEvent(dpy, KeyPressMask|KeyReleaseMask|ExposureMask, &ev); if (ev.type != KeyRelease && ev.type != KeyPress) { WMHandleEvent(&ev); @@ -247,7 +245,10 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) modifiers = ev.xkey.state & ValidModMask; if (ev.type == KeyPress) { - if (wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode +#ifdef DEBUG + printf("Got key press\n"); +#endif + if (wKeyBindings[WKBD_FOCUSNEXT].keycode == ev.xkey.keycode && wKeyBindings[WKBD_FOCUSNEXT].modifier == modifiers) { newFocused = nextToFocusAfter(newFocused); @@ -274,12 +275,18 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) } } else { +#ifdef DEBUG + printf("Got something else\n"); +#endif somethingElse = True; done = True; } } else if (ev.type == KeyRelease) { int i; +#ifdef DEBUG + printf("Got key release\n"); +#endif for (i = 0; i < 8 * keymap->max_keypermod; i++) { if (keymap->modifiermap[i] == ev.xkey.keycode && wKeyBindings[WKBD_FOCUSNEXT].modifier @@ -294,6 +301,9 @@ StartWindozeCycle(WWindow *wwin, XEvent *event, Bool next) XFreeModifiermap(keymap); if (hasModifier) { +#ifdef DEBUG + printf("Ungrabbing keyboard\n"); +#endif XUngrabKeyboard(dpy, CurrentTime); } wSetFocusTo(scr, newFocused); diff --git a/src/defaults.c b/src/defaults.c index cb16954f..de2c296e 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -155,6 +155,9 @@ static int setUTitleBack(); static int setResizebarBack(); static int setWorkspaceBack(); static int setWorkspaceSpecificBack(); +#ifdef VIRTUAL_DESKTOP +static int setVirtualEdgeThickness(); +#endif static int setMenuTitleColor(); static int setMenuTextColor(); static int setMenuDisabledColor(); @@ -436,22 +439,34 @@ WDefaultEntry optionList[] = { }, #ifdef VIRTUAL_DESKTOP {"VirtualEdgeThickness", "1", NULL, - &wPreferences.vedge_thickness, getInt, NULL + &wPreferences.vedge_thickness, getInt, setVirtualEdgeThickness }, {"VirtualEdgeExtendSpace", "0", NULL, &wPreferences.vedge_bordersize, getInt, NULL }, - {"VirtualEdgeHorizonScrollSpeed", "1", NULL, + {"VirtualEdgeHorizonScrollSpeed", "30", NULL, &wPreferences.vedge_hscrollspeed, getInt, NULL }, - {"VirtualEdgeVerticalScrollSpeed", "1", NULL, + {"VirtualEdgeVerticalScrollSpeed", "30", NULL, &wPreferences.vedge_vscrollspeed, getInt, NULL }, - {"VirtualEdgeMaximumWidth", "3000", NULL, - &wPreferences.vedge_maxwidth, getInt, NULL + {"VirtualEdgeResistance", "30", NULL, + &wPreferences.vedge_resistance, getInt, NULL + }, + {"VirtualEdgeAttraction", "30", NULL, + &wPreferences.vedge_attraction, getInt, NULL + }, + {"VirtualEdgeLeftKey", "None", (void*)WKBD_VDESK_LEFT, + NULL, getKeybind, setKeyGrab + }, + {"VirtualEdgeRightKey", "None", (void*)WKBD_VDESK_RIGHT, + NULL, getKeybind, setKeyGrab + }, + {"VirtualEdgeUpKey", "None", (void*)WKBD_VDESK_UP, + NULL, getKeybind, setKeyGrab }, - {"VirtualEdgeMaximumHeight", "3000", NULL, - &wPreferences.vedge_maxheight, getInt, NULL + {"VirtualEdgeDownKey", "None", (void*)WKBD_VDESK_DOWN, + NULL, getKeybind, setKeyGrab }, #endif {"StickyIcons", "NO", NULL, @@ -3352,6 +3367,16 @@ setWorkspaceBack(WScreen *scr, WDefaultEntry *entry, WMPropList *value, } +#ifdef VIRTUAL_DESKTOP +static int +setVirtualEdgeThickness(WScreen *scr, WDefaultEntry *entry, XColor *color, long index) +{ + wWorkspaceUpdateEdge(scr); + return 0; +} +#endif + + static int setWidgetColor(WScreen *scr, WDefaultEntry *entry, WTexture **texture, void *foo) { diff --git a/src/dialog.c b/src/dialog.c index 43a65dc6..418ec5e9 100644 --- a/src/dialog.c +++ b/src/dialog.c @@ -785,7 +785,7 @@ wIconChooserDialog(WScreen *scr, char **file, char *instance, char *class) /* check if the file the user selected is not the one that * would be loaded by default with the current search path */ *file = WMGetListSelectedItem(panel->iconList)->text; - if ((*file)[0]==0) { + if (**file==0) { wfree(*file); *file = NULL; } else { @@ -804,6 +804,8 @@ wIconChooserDialog(WScreen *scr, char **file, char *instance, char *class) *file = NULL; } + result = panel->result; + WMReleaseFont(panel->normalfont); WMUnmapWidget(panel->win); @@ -812,8 +814,6 @@ wIconChooserDialog(WScreen *scr, char **file, char *instance, char *class) wUnmanageWindow(wwin, False, False); - result= panel->result; - wfree(panel); XDestroyWindow(dpy, parent); @@ -862,8 +862,8 @@ typedef struct { #define COPYRIGHT_TEXT \ - "Copyright © 1997-2004 Alfredo K. Kojima \n"\ - "Copyright © 1998-2004 Dan Pascu " + "Copyright \xc2\xa9 1997-2004 Alfredo K. Kojima \n"\ + "Copyright \xc2\xa9 1998-2004 Dan Pascu " @@ -1314,8 +1314,6 @@ wShowInfoPanel(WScreen *scr) WMMoveWidget(panel->copyrL, 15, 185); WMSetLabelTextAlignment(panel->copyrL, WALeft); WMSetLabelText(panel->copyrL, COPYRIGHT_TEXT); - /* we want the (c) character in the font, so don't use a FontSet here */ - // fix this -Dan font = WMCreateFontWithFlags(scr->wmscreen, "SystemFont-11", WFNormalFont); font = WMSystemFontOfSize(scr->wmscreen, 11); if (font) { WMSetLabelFont(panel->copyrL, font); @@ -1368,7 +1366,7 @@ wShowInfoPanel(WScreen *scr) strbuf = wstrappend(strbuf, _("\nAdditional support for: ")); { - char *list[8]; + char *list[9]; char buf[80]; int j = 0; @@ -1384,6 +1382,9 @@ wShowInfoPanel(WScreen *scr) #ifdef OLWM_HINTS list[j++] = "OLWM"; #endif +#ifdef NETWM_HINTS + list[j++] = "WMSPEC"; +#endif buf[0] = 0; for (i = 0; i < j; i++) { @@ -1408,6 +1409,23 @@ wShowInfoPanel(WScreen *scr) strbuf = wstrappend(strbuf, _("; Antialiased text")); #endif +#ifdef VIRTUAL_DESKTOP + strbuf = wstrappend(strbuf, _("; VirtualDesktop")); +#endif + +#ifdef XINERAMA + strbuf = wstrappend(strbuf, _("\n")); +#ifdef SOLARIS_XINERAMA + strbuf = wstrappend(strbuf, _("Solaris ")); +#endif + strbuf = wstrappend(strbuf, _("Xinerama: ")); + { + char tmp[128]; + snprintf(tmp, sizeof(tmp)-1, "%d heads found.", scr->xine_info.count); + strbuf = wstrappend(strbuf, tmp); + } +#endif + panel->infoL = WMCreateLabel(panel->win); WMResizeWidget(panel->infoL, 350, 75); diff --git a/src/dock.c b/src/dock.c index daed30d2..c89fb275 100644 --- a/src/dock.c +++ b/src/dock.c @@ -956,9 +956,8 @@ launchDockedApplication(WAppIcon *btn, Bool withSelection) btn->drop_launch = 0; btn->paste_launch = withSelection; scr->last_dock = btn->dock; - btn->pid = execCommand(btn, - withSelection ? btn->paste_command : btn->command, - NULL); + btn->pid = execCommand(btn, (withSelection ? btn->paste_command : + btn->command), NULL); if (btn->pid>0) { if (btn->buggy_app) { /* give feedback that the app was launched */ @@ -972,8 +971,9 @@ launchDockedApplication(WAppIcon *btn, Bool withSelection) } else { wwarning(_("could not launch application %s\n"), btn->command); btn->launching = 0; - if (!btn->relaunching) + if (!btn->relaunching) { btn->running = 0; + } } } } @@ -1386,13 +1386,13 @@ make_icon_state(WAppIcon *btn) position = WMCreatePLString(buffer); node = WMCreatePLDictionary(dCommand, command, - dName, name, - dAutoLaunch, autolaunch, - dLock, lock, - dForced, forced, - dBuggyApplication, buggy, - dPosition, position, - NULL); + dName, name, + dAutoLaunch, autolaunch, + dLock, lock, + dForced, forced, + dBuggyApplication, buggy, + dPosition, position, + NULL); WMReleasePropList(command); WMReleasePropList(name); WMReleasePropList(position); @@ -1450,8 +1450,7 @@ dockSaveState(WDock *dock) } } - dock_state = WMCreatePLDictionary(dApplications, list, - NULL); + dock_state = WMCreatePLDictionary(dApplications, list, NULL); if (dock->type == WM_DOCK) { snprintf(buffer, sizeof(buffer), "Applications%i", dock->screen_ptr->scr_height); @@ -1512,9 +1511,8 @@ wDockSaveState(WScreen *scr, WMPropList *old_state) if (strncasecmp(WMGetFromPLString(tmp), "applications", 12) == 0 && !WMGetFromPLDictionary(dock_state, tmp)) { - WMPutInPLDictionary(dock_state, - tmp, - WMGetFromPLDictionary(old_state, tmp)); + WMPutInPLDictionary(dock_state, tmp, + WMGetFromPLDictionary(old_state, tmp)); } } WMReleasePropList(keys); @@ -1774,9 +1772,9 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dPosition); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("Position"); - else { + } else { WMRect rect; int flags; @@ -1795,12 +1793,13 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) wScreenKeepInside(scr, &x, &dock->y_pos, ICON_SIZE, ICON_SIZE); } - /* This is no more needed. ??? */ + /* Is this needed any more? */ if (type == WM_CLIP) { - if (dock->x_pos < 0) + if (dock->x_pos < 0) { dock->x_pos = 0; - else if (dock->x_pos > scr->scr_width-ICON_SIZE) + } else if (dock->x_pos > scr->scr_width-ICON_SIZE) { dock->x_pos = scr->scr_width-ICON_SIZE; + } } else { if (dock->x_pos >= 0) { dock->x_pos = DOCK_EXTRA_SPACE; @@ -1820,11 +1819,12 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dLowered); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("Lowered"); - else { - if (strcasecmp(WMGetFromPLString(value), "YES")==0) + } else { + if (strcasecmp(WMGetFromPLString(value), "YES")==0) { dock->lowered = 1; + } } } @@ -1836,11 +1836,12 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dCollapsed); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("Collapsed"); - else { - if (strcasecmp(WMGetFromPLString(value), "YES")==0) + } else { + if (strcasecmp(WMGetFromPLString(value), "YES")==0) { dock->collapsed = 1; + } } } @@ -1850,9 +1851,9 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dAutoCollapse); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("AutoCollapse"); - else { + } else { if (strcasecmp(WMGetFromPLString(value), "YES")==0) { dock->auto_collapse = 1; dock->collapsed = 1; @@ -1866,9 +1867,9 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dAutoRaiseLower); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("AutoRaiseLower"); - else { + } else { if (strcasecmp(WMGetFromPLString(value), "YES")==0) { dock->auto_raise_lower = 1; } @@ -1882,11 +1883,12 @@ wDockRestoreState(WScreen *scr, WMPropList *dock_state, int type) value = WMGetFromPLDictionary(dock_state, dAutoAttractIcons); if (value) { - if (!WMIsPLString(value)) + if (!WMIsPLString(value)) { COMPLAIN("AutoAttractIcons"); - else { - if (strcasecmp(WMGetFromPLString(value), "YES")==0) + } else { + if (strcasecmp(WMGetFromPLString(value), "YES")==0) { dock->attract_icons = 1; + } } } @@ -2136,21 +2138,19 @@ Bool wDockAttachIcon(WDock *dock, WAppIcon *icon, int x, int y) { WWindow *wwin; - char **argv; - int argc; int index; wwin = icon->icon->owner; if (icon->command==NULL) { - icon->editing = 0; - if (XGetCommand(dpy, wwin->client_win, &argv, &argc) && argc>0) { + char *command; - icon->command = wtokenjoin(argv, argc); - XFreeStringList(argv); - } else { - char *command=NULL; + icon->editing = 0; -/* icon->forced_dock = 1;*/ + command = GetCommandForWindow(wwin->client_win); + if (command) { + icon->command = command; + } else { + /* icon->forced_dock = 1;*/ if (dock->type!=WM_CLIP || !icon->attracted) { icon->editing = 1; if (wInputDialog(dock->screen_ptr, _("Dock Icon"), @@ -2181,7 +2181,7 @@ wDockAttachIcon(WDock *dock, WAppIcon *icon, int x, int y) } } } - } + } } else { icon->editing = 0; } @@ -2266,8 +2266,7 @@ Bool moveIconBetweenDocks(WDock *src, WDock *dest, WAppIcon *icon, int x, int y) { WWindow *wwin; - char **argv; - int argc; + char *command; int index; if (src == dest) @@ -2285,15 +2284,12 @@ moveIconBetweenDocks(WDock *src, WDock *dest, WAppIcon *icon, int x, int y) * moved icons it applies. -Dan */ if ((dest->type==WM_DOCK /*|| dest->keep_attracted*/) && icon->command==NULL) { - if (XGetCommand(dpy, wwin->client_win, &argv, &argc) && argc>0) { - - icon->command = wtokenjoin(argv, argc); - XFreeStringList(argv); + command = GetCommandForWindow(wwin->client_win); + if (command) { + icon->command = command; } else { - char *command=NULL; - icon->editing = 1; -/* icon->forced_dock = 1;*/ + /* icon->forced_dock = 1;*/ if (wInputDialog(src->screen_ptr, _("Dock Icon"), _("Type the command used to launch the application"), &command)) { @@ -3177,22 +3173,15 @@ wDockTrackWindowLaunch(WDock *dock, Window window) Bool found = False; char *command = NULL; - { - int argc; - char **argv; - - if (XGetCommand(dpy, window, &argv, &argc)) { - if (argc > 0 && argv != NULL) - command = wtokenjoin(argv, argc); - if (argv) { - XFreeStringList(argv); - } - } - } + command = GetCommandForWindow(window); if (!PropGetWMClass(window, &wm_class, &wm_instance) || - (!wm_class && !wm_instance)) - return; + (!wm_class && !wm_instance)) { + + if (command) + wfree(command); + return; + } retry: for (i=0; imax_icons; i++) { @@ -3232,9 +3221,9 @@ retry: icon->forced_dock = 1; icon->running = 0; } - if (!icon->forced_dock) - icon->main_window = window; - + if (!icon->forced_dock) { + icon->main_window = window; + } } found = True; if (!wPreferences.no_animations && !icon->launching && @@ -3598,8 +3587,7 @@ iconDblClick(WObjDescriptor *desc, XEvent *event) wWorkspaceChange(dock->screen_ptr, wapp->last_workspace); } - wUnhideApplication(wapp, event->xbutton.button==Button2, - unhideHere); + wUnhideApplication(wapp, event->xbutton.button==Button2, unhideHere); if (event->xbutton.state & MOD_MASK) { wHideOtherApplications(btn->icon->owner); @@ -3620,9 +3608,8 @@ iconDblClick(WObjDescriptor *desc, XEvent *event) (!btn->running || (event->xbutton.state & ControlMask))) { launchDockedApplication(btn, False); } - } else if (btn->xindex == 0 && btn->yindex == 0 - && btn->dock->type == WM_DOCK) { - + } else if (btn->xindex==0 && btn->yindex==0 && + btn->dock->type==WM_DOCK) { wShowGNUstepPanel(dock->screen_ptr); } } diff --git a/src/event.c b/src/event.c index 484de816..d5cab4dc 100644 --- a/src/event.c +++ b/src/event.c @@ -66,9 +66,13 @@ #ifdef KWM_HINTS # include "kwm.h" #endif +#ifdef NETWM_HINTS +# include "wmspec.h" +#endif /******** Global Variables **********/ extern XContext wWinContext; +extern XContext wVEdgeContext; extern Cursor wCursor[WCUR_LAST]; @@ -323,7 +327,7 @@ void EventLoop() { XEvent event; - + for(;;) { WMNextEvent(dpy, &event); WMHandleEvent(&event); @@ -331,6 +335,39 @@ EventLoop() } +/* + *---------------------------------------------------------------------- + * ProcessPendingEvents -- + * Processes the events that are currently pending (at the time + * this function is called) in the display's queue. + * + * Returns: + * After the pending events that were present at the function call + * are processed. + * + * Side effects: + * Many -- whatever handling events may involve. + * + *---------------------------------------------------------------------- + */ +void +ProcessPendingEvents() +{ + XEvent event; + int count; + + XSync(dpy, False); + + /* Take a snapshot of the event count in the queue */ + count = XPending(dpy); + + while (count>0 && XPending(dpy)) { + WMNextEvent(dpy, &event); + WMHandleEvent(&event); + count--; + } +} + Bool IsDoubleClick(WScreen *scr, XEvent *event) @@ -478,7 +515,7 @@ handleMapRequest(XEvent *ev) Window window = ev->xmaprequest.window; #ifdef DEBUG - L("got map request for %x\n", (unsigned)window); + printf("got map request for %x\n", (unsigned)window); #endif if ((wwin = wWindowFor(window))) { if (wwin->flags.shaded) { @@ -553,7 +590,7 @@ handleDestroyNotify(XEvent *event) int index; #ifdef DEBUG - L("got destroy notify"); + printf("got destroy notify\n"); #endif wwin = wWindowFor(window); if (wwin) { @@ -607,7 +644,7 @@ handleExpose(XEvent *event) XEvent ev; #ifdef DEBUG - L("got expose"); + printf("got expose\n"); #endif while (XCheckTypedWindowEvent(dpy, event->xexpose.window, Expose, &ev)); @@ -662,7 +699,7 @@ handleButtonPress(XEvent *event) WScreen *scr; #ifdef DEBUG - L("got button press"); + printf("got button press\n"); #endif scr = wScreenForRootWindow(event->xbutton.root); @@ -749,7 +786,7 @@ handleMapNotify(XEvent *event) { WWindow *wwin; #ifdef DEBUG - L("got map"); + printf("got map\n"); #endif wwin = wWindowFor(event->xmap.event); if (wwin && wwin->client_win == event->xmap.event) { @@ -772,7 +809,7 @@ handleUnmapNotify(XEvent *event) XEvent ev; Bool withdraw = False; #ifdef DEBUG - L("got unmap"); + printf("got unmap\n"); #endif /* only process windows with StructureNotify selected * (ignore SubstructureNotify) */ @@ -824,7 +861,7 @@ handleConfigureRequest(XEvent *event) { WWindow *wwin; #ifdef DEBUG - L("got configure request"); + printf("got configure request\n"); #endif if (!(wwin=wWindowFor(event->xconfigurerequest.window))) { /* @@ -847,7 +884,7 @@ handlePropertyNotify(XEvent *event) unsigned int ju; WScreen *scr; #ifdef DEBUG - L("got property notify"); + printf("got property notify\n"); #endif if ((wwin=wWindowFor(event->xproperty.window))) { if (!XGetGeometry(dpy, wwin->client_win, &jr, &ji, &ji, @@ -876,7 +913,7 @@ handleClientMessage(XEvent *event) WWindow *wwin; WObjDescriptor *desc; #ifdef DEBUG - L("got client message"); + printf("got client message\n"); #endif /* handle transition from Normal to Iconic state */ if (event->xclient.message_type == _XA_WM_CHANGE_STATE @@ -962,6 +999,10 @@ handleClientMessage(XEvent *event) wFrameWindowChangeState(wwin->frame, WS_FOCUSED); break; } +#ifdef NETWM_HINTS + } else if (wNETWMProcessClientMessage(&event->xclient)) { + /* do nothing */ +#endif #ifdef GNOME_STUFF } else if (wGNOMEProcessClientMessage(&event->xclient)) { /* do nothing */ @@ -1035,34 +1076,19 @@ handleEnterNotify(XEvent *event) { WWindow *wwin; WObjDescriptor *desc = NULL; +#ifdef VIRTUAL_DESKTOP + void (*vdHandler)(XEvent * event); +#endif XEvent ev; WScreen *scr = wScreenForRootWindow(event->xcrossing.root); #ifdef DEBUG - L("got enter notify"); + printf("got enter notify\n"); #endif #ifdef VIRTUAL_DESKTOP - /* TODO: acceleration code */ - if (wPreferences.vedge_thickness) { - int x,y; - if (event->xcrossing.window == scr->virtual_edge_r) { - XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, scr->scr_width - wPreferences.vedge_thickness - 1, event->xcrossing.y_root); - wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); - wWorkspaceSetViewPort(scr, scr->current_workspace, x + VIRTUALEDGE_SCROLL_HSTEP, y); - } else if (event->xcrossing.window == scr->virtual_edge_l) { - XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, wPreferences.vedge_thickness + 1, event->xcrossing.y_root); - wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); - wWorkspaceSetViewPort(scr, scr->current_workspace, x - VIRTUALEDGE_SCROLL_HSTEP, y); - } else if (event->xcrossing.window == scr->virtual_edge_u) { - XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, event->xcrossing.x_root, wPreferences.vedge_thickness + 1); - wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); - wWorkspaceSetViewPort(scr, scr->current_workspace, x, y - VIRTUALEDGE_SCROLL_VSTEP); - } else if (event->xcrossing.window == scr->virtual_edge_d) { - printf("enter bottom\n"); - XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, event->xcrossing.x_root, scr->scr_height - wPreferences.vedge_thickness - 1); - wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); - wWorkspaceSetViewPort(scr, scr->current_workspace, x, y + VIRTUALEDGE_SCROLL_VSTEP); - } + if (XFindContext(dpy, event->xcrossing.window, wVEdgeContext, + (XPointer *)&vdHandler)!=XCNOENT) { + (*vdHandler)( event); } #endif @@ -1178,7 +1204,7 @@ handleShapeNotify(XEvent *event) WWindow *wwin; XEvent ev; #ifdef DEBUG - L("got shape notify"); + printf("got shape notify\n"); #endif while (XCheckTypedWindowEvent(dpy, shev->window, event->type, &ev)) { XShapeEvent *sev = (XShapeEvent*)&ev; @@ -1446,7 +1472,7 @@ handleKeyPress(XEvent *event) } break; case WKBD_MAXIMIZE: - if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_resizable)) { + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { int newdir = (MAX_VERTICAL|MAX_HORIZONTAL); CloseWindowMenu(scr); @@ -1459,7 +1485,7 @@ handleKeyPress(XEvent *event) } break; case WKBD_VMAXIMIZE: - if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_resizable)) { + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { int newdir = (MAX_VERTICAL ^ wwin->flags.maximized); CloseWindowMenu(scr); @@ -1472,7 +1498,7 @@ handleKeyPress(XEvent *event) } break; case WKBD_HMAXIMIZE: - if (ISMAPPED(wwin) && ISFOCUSED(wwin) && !WFLAGP(wwin, no_resizable)) { + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { int newdir = (MAX_HORIZONTAL ^ wwin->flags.maximized); CloseWindowMenu(scr); @@ -1515,7 +1541,8 @@ handleKeyPress(XEvent *event) } break; case WKBD_MOVERESIZE: - if (ISMAPPED(wwin) && ISFOCUSED(wwin)) { + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && + (IS_RESIZABLE(wwin) || IS_MOVABLE(wwin))) { CloseWindowMenu(scr); wKeyboardMoveResizeWindow(wwin); @@ -1718,6 +1745,23 @@ handleKeyPress(XEvent *event) } break; #endif /* KEEP_XKB_LOCK_STATUS */ +#ifdef VIRTUAL_DESKTOP + case WKBD_VDESK_LEFT: + wWorkspaceKeyboardMoveDesktop(scr, VEC_LEFT); + break; + + case WKBD_VDESK_RIGHT: + wWorkspaceKeyboardMoveDesktop(scr, VEC_RIGHT); + break; + + case WKBD_VDESK_UP: + wWorkspaceKeyboardMoveDesktop(scr, VEC_UP); + break; + + case WKBD_VDESK_DOWN: + wWorkspaceKeyboardMoveDesktop(scr, VEC_DOWN); + break; +#endif } } @@ -1739,7 +1783,7 @@ handleMotionNotify(XEvent *event) p.y >= (rect.pos.y + rect.size.height - 2)) { WMenu *menu; #ifdef DEBUG - L("pointer at screen edge"); + printf("pointer at screen edge\n"); #endif menu = wMenuUnderPointer(scr); if (menu!=NULL) @@ -1773,13 +1817,13 @@ handleMotionNotify(XEvent *event) && event->xmotion.x_root >= wwin->frame_x && event->xmotion.x_root <= wwin->frame_x + wwin->frame->core->width) { - if (!WFLAGP(wwin, no_titlebar) + if (HAS_BORDER(wwin) && wwin->frame_y <= - wwin->frame->top_width) { wWindowMove(wwin, wwin->frame_x, 0); wwin->flags.dragged_while_fmaximized = 0; - } else if (!WFLAGP(wwin, no_resizebar) + } else if (HAS_RESIZEBAR(wwin) && wwin->frame_y + wwin->frame->core->height >= scr->scr_height + wwin->frame->bottom_width) { diff --git a/src/framewin.c b/src/framewin.c index ce64c223..8e32326f 100644 --- a/src/framewin.c +++ b/src/framewin.c @@ -1488,11 +1488,13 @@ titlebarMouseDown(WObjDescriptor *desc, XEvent *event) WCoreWindow *titlebar = desc->self; if (IsDoubleClick(fwin->core->screen_ptr, event)) { - if (fwin->on_dblclick_titlebar) - (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, 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); + if (fwin->on_mousedown_titlebar) { + (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event); + } } } @@ -1534,8 +1536,9 @@ buttonMouseDown(WObjDescriptor *desc, XEvent *event) } #ifdef XKB_BUTTON_HINT if (button == fwin->language_button) { - if (!wPreferences.modelock) return; - image = fwin->languagebutton_image; + if (!wPreferences.modelock) + return; + image = fwin->languagebutton_image; } #endif diff --git a/src/funcs.h b/src/funcs.h index 2ecc6c71..86dc4cc5 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -152,6 +152,18 @@ void ExecExitScript(); Bool wFetchName(Display *dpy, Window win, char **winname); Bool wGetIconName(Display *dpy, Window win, char **iconname); +/* Free returned string it when done. (applies to the next 2 functions) */ +char* GetCommandForWindow(Window win); +char* GetProgramNameForWindow(Window win); + +Bool GetCommandForPid(int pid, char ***argv, int *argc); + +#ifdef NETWM_HINTS +#include "wmspec.h" +#define GetPidForWindow(win) wNETWMGetPidForWindow(win) +#else +int GetPidForWindow(Window win); +#endif #endif diff --git a/src/icon.c b/src/icon.c index fc5333cc..86efbb03 100644 --- a/src/icon.c +++ b/src/icon.c @@ -166,6 +166,11 @@ wIconCreate(WWindow *wwin) #else icon->show_title = 1; #endif +#ifdef NETWM_HINTS + if (!icon->image && !WFLAGP(wwin, always_user_icon)) + icon->image = RRetainImage(wwin->net_icon_image); + if (!icon->image) +#endif icon->image = wDefaultGetImage(scr, wwin->wm_instance, wwin->wm_class); file = wDefaultGetIconFile(scr, wwin->wm_instance, wwin->wm_class, @@ -631,7 +636,11 @@ wIconUpdate(WIcon *icon) icon->pixmap = None; - if (wwin && WFLAGP(wwin, always_user_icon)) + if (wwin && (WFLAGP(wwin, always_user_icon) +#ifdef NETWM_HINTS + || wwin->net_icon_image +#endif + )) goto user_icon; /* use client specified icon window */ diff --git a/src/keybind.h b/src/keybind.h index b2f0aef7..90004e1d 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -79,11 +79,21 @@ #define WKBD_SWITCH_SCREEN 45 #ifdef KEEP_XKB_LOCK_STATUS -# define WKBD_TOGGLE 46 -# define WKBD_LAST 47 +# define WKBD_TOGGLE 46 +# define WKBD_TMP 47 #else -# define WKBD_LAST 46 -#endif /* KEEP_XKB_LOCK_STATUS */ +# define WKBD_TMP 46 +#endif + +#ifdef VIRTUAL_DESKTOP +# define WKBD_VDESK_LEFT WKBD_TMP +# define WKBD_VDESK_RIGHT (WKBD_TMP+1) +# define WKBD_VDESK_UP (WKBD_TMP+2) +# define WKBD_VDESK_DOWN (WKBD_TMP+3) +# define WKBD_LAST (WKBD_TMP+4) +#else +# define WKBD_LAST WKBD_TMP +#endif /* VIRTUAL_DESKTOP */ typedef struct WShortKey { diff --git a/src/main.c b/src/main.c index 8f2103db..9f6a23d5 100644 --- a/src/main.c +++ b/src/main.c @@ -85,6 +85,7 @@ WDDomain *WDRootMenu = NULL; XContext wWinContext; XContext wAppWinContext; XContext wStackContext; +XContext wVEdgeContext; /* Atoms */ Atom _XA_WM_STATE; @@ -123,9 +124,9 @@ Atom _XA_DND_SELECTION; Cursor wCursor[WCUR_LAST]; /* last event timestamp for XSetInputFocus */ -Time LastTimestamp; +Time LastTimestamp = CurrentTime; /* timestamp on the last time we did XSetInputFocus() */ -Time LastFocusChange; +Time LastFocusChange = CurrentTime; #ifdef SHAPE Bool wShapeSupported; @@ -494,8 +495,10 @@ check_defaults() static void execInitScript() { - char *file; - char *paths = wstrconcat(wusergnusteppath(), ":"DEF_CONFIG_PATHS); + char *file, *paths; + + paths = wstrconcat(wusergnusteppath(), "/Library/WindowMaker"); + paths = wstrappend(paths, ":"DEF_CONFIG_PATHS); file = wfindfile(paths, DEF_INIT_SCRIPT); wfree(paths); @@ -519,8 +522,10 @@ execInitScript() void ExecExitScript() { - char *file; - char *paths = wstrconcat(wusergnusteppath(), ":"DEF_CONFIG_PATHS); + char *file, *paths; + + paths = wstrconcat(wusergnusteppath(), "/Library/WindowMaker"); + paths = wstrappend(paths, ":"DEF_CONFIG_PATHS); file = wfindfile(paths, DEF_EXIT_SCRIPT); wfree(paths); @@ -717,22 +722,25 @@ main(int argc, char **argv) } - if (!Locale) { - Locale = getenv("LC_ALL"); - } - if (!Locale) { - Locale = getenv("LANG"); + if (Locale) { + /* return of wstrconcat should not be free-ed! read putenv man page */ + putenv(wstrconcat("LANG=", Locale)); + } else { + Locale = getenv("LC_ALL"); + if (!Locale) { + Locale = getenv("LANG"); + } } setlocale(LC_ALL, ""); if (!Locale || strcmp(Locale, "C")==0 || strcmp(Locale, "POSIX")==0) - Locale = NULL; + Locale = NULL; #ifdef I18N if (getenv("NLSPATH")) - bindtextdomain("WindowMaker", getenv("NLSPATH")); + bindtextdomain("WindowMaker", getenv("NLSPATH")); else - bindtextdomain("WindowMaker", LOCALEDIR); + bindtextdomain("WindowMaker", LOCALEDIR); textdomain("WindowMaker"); if (!XSupportsLocale()) { diff --git a/src/menu.c b/src/menu.c index 8edb573a..18496093 100644 --- a/src/menu.c +++ b/src/menu.c @@ -43,6 +43,7 @@ #include "stacking.h" #include "text.h" #include "xinerama.h" +#include "workspace.h" /****** Global Variables ******/ @@ -2259,9 +2260,7 @@ byebye: ((WMenu*)desc->parent)->flags.inside_handler = 0; #ifdef VIRTUAL_DESKTOP - if (wPreferences.vedge_thickness) { wWorkspaceRaiseEdge(scr); - } #endif } @@ -2510,7 +2509,7 @@ wMenuSaveState(WScreen *scr) WMPropList *menus, *key; int save_menus = 0; - menus = WMCreatePLDictionary(NULL, NULL, NULL); + menus = WMCreatePLDictionary(NULL, NULL); #ifndef LITE if (scr->switch_menu && scr->switch_menu->flags.buttoned) { diff --git a/src/misc.c b/src/misc.c index d3ddf523..17dc4917 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,8 +1,8 @@ -/* +/* * Window Maker window manager - * + * * Copyright (c) 1997-2003 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 @@ -15,7 +15,7 @@ * * 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, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "wconfig.h" @@ -52,8 +52,6 @@ /**** global variables *****/ -extern char *DisplayName; - extern WPreferences wPreferences; extern Time LastTimestamp; @@ -91,7 +89,7 @@ static char* username() { char *tmp; - + tmp = getlogin(); if (!tmp) { struct passwd *user; @@ -109,7 +107,7 @@ username() } return tmp; } - + char * MakeCPPArgs(char *path) { @@ -117,7 +115,7 @@ MakeCPPArgs(char *path) char buffer[MAXLINE], *buf, *line; Visual *visual; char *tmp; - + line = wmalloc(MAXLINE); *line = 0; i=1; @@ -125,13 +123,13 @@ MakeCPPArgs(char *path) if (buf[0]=='(') { wwarning(_("your machine is misconfigured. HOSTNAME is set to %s"), buf); - } else + } else putdef(line, " -DHOST=", buf); } else if ((buf=getenv("HOST"))!=NULL) { if (buf[0]=='(') { wwarning(_("your machine is misconfigured. HOST is set to %s"), buf); - } else + } else putdef(line, " -DHOST=", buf); } buf = username(); @@ -141,14 +139,14 @@ MakeCPPArgs(char *path) buf = XDisplayName(DisplayString(dpy)); putdef(line, " -DDISPLAY=", buf); putdef(line, " -DWM_VERSION=", VERSION); - + visual = DefaultVisual(dpy, DefaultScreen(dpy)); putidef(line, " -DVISUAL=", visual->class); - + putidef(line, " -DDEPTH=", DefaultDepth(dpy, DefaultScreen(dpy))); putidef(line, " -DSCR_WIDTH=", WidthOfScreen(DefaultScreenOfDisplay(dpy))); - putidef(line, " -DSCR_HEIGHT=", + putidef(line, " -DSCR_HEIGHT=", HeightOfScreen(DefaultScreenOfDisplay(dpy))); /* put the dir where the menu is being read from to the @@ -181,7 +179,7 @@ MakeCPPArgs(char *path) char * wgethomedir(); /* home is statically allocated. Don't free it! */ char *home = wgethomedir(); - + strcpy(fullpath, home); strcat(fullpath, &(buf[1])); } @@ -189,7 +187,7 @@ MakeCPPArgs(char *path) putdef(line, " -I", fullpath); } while ((buf = strtok(NULL, ":"))!=NULL); - + #undef arg #ifdef DEBUG puts("CPP ARGS"); @@ -211,14 +209,14 @@ isBelow(WWindow *win1, WWindow *win2) { int i; WCoreWindow *tmp; - + tmp = win1->frame->core->stacking->under; while (tmp) { if (tmp == win2->frame->core) return True; tmp = tmp->stacking->under; } - + for (i=win1->frame->core->stacking->window_level-1; i>=0; i--) { tmp = win1->screen_ptr->stacking_list[i]; while (tmp) { @@ -272,7 +270,7 @@ char **winname; } else { /* the hint is probably not set */ *winname = NULL; - + return False; } } @@ -291,7 +289,7 @@ char **iconname; XTextProperty text_prop; char **list; int num; - + if (XGetWMIconName(dpy, win, &text_prop) != 0 && text_prop.value && text_prop.nitems > 0) { if (text_prop.encoding == XA_STRING) @@ -313,20 +311,20 @@ char **iconname; } -static void +static void eatExpose() { XEvent event, foo; - + /* compress all expose events into a single one */ - + if (XCheckMaskEvent(dpy, ExposureMask, &event)) { /* ignore other exposure events for this window */ while (XCheckWindowEvent(dpy, event.xexpose.window, ExposureMask, &foo)); /* eat exposes for other windows */ eatExpose(); - + event.xexpose.count = 0; XPutBackEvent(dpy, &event); } @@ -351,8 +349,8 @@ SlideWindow(Window win, int from_x, int from_y, int to_x, int to_y) {ICON_SLIDE_DELAY_M, ICON_SLIDE_STEPS_M, ICON_SLIDE_SLOWDOWN_M}, {ICON_SLIDE_DELAY_S, ICON_SLIDE_STEPS_S, ICON_SLIDE_SLOWDOWN_S}, {ICON_SLIDE_DELAY_US, ICON_SLIDE_STEPS_US, ICON_SLIDE_SLOWDOWN_US}}; - - + + dx = (float)(to_x-from_x); dy = (float)(to_y-from_y); @@ -477,7 +475,7 @@ ShrinkString(WMFont *font, char *string, int width) } else if (winfo_window, clipboard); - + XConvertSelection(dpy, selection, XA_STRING, clipboard, screen->info_window, CurrentTime); - + timer = WMAddTimerHandler(1000, timeoutHandler, &timeout); - + while (!XCheckTypedWindowEvent(dpy, screen->info_window, SelectionNotify, &ev) && !timeout); - + if (!timeout) { WMDeleteTimerHandler(timer); } else { @@ -607,7 +605,7 @@ static char* getselection(WScreen *scr) { char *tmp; - + tmp = getTextSelection(scr, XA_PRIMARY); if (!tmp) tmp = getTextSelection(scr, XA_CUT_BUFFER0); @@ -623,10 +621,10 @@ getuserinput(WScreen *scr, char *line, int *ptr) char *prompt; int j, state; int begin = 0; -#define BUFSIZE 512 +#define BUFSIZE 512 char tbuffer[BUFSIZE], pbuffer[BUFSIZE]; - + title = _("Program Arguments"); prompt = _("Enter command arguments:"); ret = NULL; @@ -716,17 +714,17 @@ get_dnd_selection(WScreen *scr) char **list; char *flat_string; int count; - + result=XGetTextProperty(dpy, scr->root_win, &text_ret, _XA_DND_SELECTION); - + if (result==0 || text_ret.value==NULL || text_ret.encoding==None || text_ret.format==0 || text_ret.nitems == 0) { wwarning(_("unable to get dropped data from DND drop")); return NULL; } - + XTextPropertyToStringList(&text_ret, &list, &count); - + if (!list || count<1) { XFree(text_ret.value); wwarning(_("error getting dropped data from DND drop")); @@ -737,7 +735,7 @@ get_dnd_selection(WScreen *scr) if (!flat_string) { wwarning(_("out of memory while getting data from DND drop")); } - + XFreeStringList(list); XFree(text_ret.value); return flat_string; @@ -749,7 +747,7 @@ get_dnd_selection(WScreen *scr) #define S_ESCAPE 1 #define S_OPTION 2 -/* +/* * state input new-state output * NORMAL % OPTION * NORMAL \ ESCAPE @@ -808,15 +806,15 @@ ExpandOptions(WScreen *scr, char *cmdline) case 'n': out[optr++]=10; break; - + case 'r': out[optr++]=13; break; - + case 't': out[optr++]=9; break; - + default: out[optr++]=cmdline[ptr]; } @@ -828,7 +826,7 @@ ExpandOptions(WScreen *scr, char *cmdline) case 'w': if (scr->focused_window && scr->focused_window->flags.focused) { - snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", + snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->focused_window->client_win); slen = strlen(tmpbuf); olen += slen; @@ -844,9 +842,9 @@ ExpandOptions(WScreen *scr, char *cmdline) out[optr++]=' '; } break; - + case 'W': - snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", + snprintf(tmpbuf, sizeof(tmpbuf), "0x%x", (unsigned int)scr->current_workspace + 1); slen = strlen(tmpbuf); olen += slen; @@ -859,10 +857,10 @@ ExpandOptions(WScreen *scr, char *cmdline) strcat(out,tmpbuf); optr+=slen; break; - + case 'a': ptr++; - user_input = getuserinput(scr, cmdline, &ptr); + user_input = getuserinput(scr, cmdline, &ptr); if (user_input) { slen = strlen(user_input); olen += slen; @@ -907,7 +905,7 @@ ExpandOptions(WScreen *scr, char *cmdline) optr+=slen; break; #endif /* OFFIX_DND */ - + case 's': if (!selection) { selection = getselection(scr); @@ -940,7 +938,7 @@ ExpandOptions(WScreen *scr, char *cmdline) if (selection) XFree(selection); return out; - + error: wfree(out); if (selection) @@ -1007,21 +1005,21 @@ GetShortcutString(char *text) /* KeySym ksym;*/ int control = 0; char *tmp; - + tmp = text = wstrdup(text); /* get modifiers */ while ((k = strchr(text, '+'))!=NULL) { int mod; - + *k = 0; mod = wXModifierFromKey(text); if (mod<0) { return wstrdup("bug"); } - + modmask |= mod; - + if (strcasecmp(text, "Meta")==0) { buffer = wstrappend(buffer, "M+"); } else if (strcasecmp(text, "Alt")==0) { @@ -1029,15 +1027,15 @@ GetShortcutString(char *text) } else if (strcasecmp(text, "Shift")==0) { buffer = wstrappend(buffer, "Sh+"); } else if (strcasecmp(text, "Mod1")==0) { - buffer = wstrappend(buffer, "M1+"); + buffer = wstrappend(buffer, "M1+"); } else if (strcasecmp(text, "Mod2")==0) { - buffer = wstrappend(buffer, "M2+"); + buffer = wstrappend(buffer, "M2+"); } else if (strcasecmp(text, "Mod3")==0) { buffer = wstrappend(buffer, "M3+"); } else if (strcasecmp(text, "Mod4")==0) { - buffer = wstrappend(buffer, "M4+"); + buffer = wstrappend(buffer, "M4+"); } else if (strcasecmp(text, "Mod5")==0) { - buffer = wstrappend(buffer, "M5+"); + buffer = wstrappend(buffer, "M5+"); } else if (strcasecmp(text, "Control")==0) { control = 1; } else { @@ -1050,7 +1048,7 @@ GetShortcutString(char *text) buffer = wstrappend(buffer, "^"); } buffer = wstrappend(buffer, text); - + /* get key */ /* ksym = XStringToKeysym(text); tmp = keysymToString(ksym, modmask); @@ -1185,7 +1183,7 @@ SendHelperMessage(WScreen *scr, char type, int workspace, char *msg) if (!scr->flags.backimage_helper_launched) { return; } - + len = (msg ? strlen(msg) : 0) + (workspace >=0 ? 4 : 0) + 1 ; buffer = wmalloc(len+5); snprintf(buf, len, "%4i", len); @@ -1244,22 +1242,141 @@ UpdateDomainFile(WDDomain *domain) } - char* StrConcatDot(char *a, char *b) { int len; char *str; - + if (!a) a = ""; if (!b) b = ""; - + len = strlen(a)+strlen(b)+4; str = wmalloc(len); - + snprintf(str, len, "%s.%s", a, b); - + return str; } + + +#ifndef NETWM_HINTS + +static Atom net_wm_pid = None; + +int +GetPidForWindow(Window win) +{ + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + int pid; + + if (net_wm_pid == None) { + net_wm_pid = XInternAtom(dpy, "_NET_WM_PID", False); + } + + if (XGetWindowProperty(dpy, win, net_wm_pid, 0, 1, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)==Success && data) { + + pid = *data; + XFree(data); + } else { + pid = 0; + } + + return pid; +} + +#endif + + +Bool +GetCommandForPid(int pid, char ***argv, int *argc) +{ + char buf[1024]; + FILE *fPtr; + int count, i, j; + + sprintf(buf, "/proc/%d/cmdline", pid); + fPtr = fopen(buf, "r"); + if (fPtr) { + count = read(fileno(fPtr), buf, 1024); + if (count > 0) { + buf[count] = 0; + for (i=0, *argc=0; i 0 && argv != NULL) { + if (elements==0) + elements = argc; + command = wtokenjoin(argv, WMIN(argc, elements)); + if (command[0] == 0) { + wfree(command); + command = NULL; + } + } + if (argv) { + XFreeStringList(argv); + } + } + + return command; +} + + +/* Free result when done */ +char* +GetCommandForWindow(Window win) +{ + return getCommandForWindow(win, 0); +} + + +/* Free result when done */ +char* +GetProgramNameForWindow(Window win) +{ + return getCommandForWindow(win, 1); +} + + diff --git a/src/moveres.c b/src/moveres.c index 5dd0d8ae..eaf7bb3c 100644 --- a/src/moveres.c +++ b/src/moveres.c @@ -66,7 +66,7 @@ /* True if window currently has a border. This also includes borderless * windows which are currently selected */ -#define HAS_BORDER(w) ((w)->flags.selected || !WFLAGP((w), no_border)) +#define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w)) /****** Global Variables ******/ @@ -236,8 +236,7 @@ mapPositionDisplay(WWindow *wwin, int x, int y, int w, int h) return; } else if (wPreferences.move_display == WDIS_CENTER) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); - moveGeometryDisplayCentered(scr, - rect.pos.x + rect.size.width/2, + moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2); } else if (wPreferences.move_display == WDIS_TOPLEFT) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); @@ -265,7 +264,7 @@ showGeometry(WWindow *wwin, int x1, int y1, int x2, int y2, int direction) * x2-1 everywhere below in the code). But why only for x? */ x1--; x2--; - if (HAS_BORDER(wwin)) { + if (HAS_BORDER_WITH_SELECT(wwin)) { x1 += FRAME_BORDER_WIDTH; x2 += FRAME_BORDER_WIDTH; y1 += FRAME_BORDER_WIDTH; @@ -407,8 +406,7 @@ cycleGeometryDisplay(WWindow *wwin, int x, int y, int w, int h, int dir) } else { if (wPreferences.size_display == WDIS_CENTER) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); - moveGeometryDisplayCentered(scr, - rect.pos.x + rect.size.width/2, + moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2); } else if (wPreferences.size_display == WDIS_TOPLEFT) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); @@ -434,8 +432,7 @@ mapGeometryDisplay(WWindow *wwin, int x, int y, int w, int h) if (wPreferences.size_display == WDIS_CENTER) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); - moveGeometryDisplayCentered(scr, - rect.pos.x + rect.size.width/2, + moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width/2, rect.pos.y + rect.size.height/2); } else if (wPreferences.size_display == WDIS_TOPLEFT) { rect = wGetRectForHead(scr, wGetHeadForWindow(wwin)); @@ -497,15 +494,15 @@ drawTransparentFrame(WWindow *wwin, int x, int y, int width, int height) int h = 0; int bottom = 0; - if (HAS_BORDER(wwin)) { + if (HAS_BORDER_WITH_SELECT(wwin)) { x += FRAME_BORDER_WIDTH; y += FRAME_BORDER_WIDTH; } - if (!WFLAGP(wwin, no_titlebar) && !wwin->flags.shaded) { + if (HAS_TITLEBAR(wwin) && !wwin->flags.shaded) { h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2; } - if (!WFLAGP(wwin, no_resizebar) && !wwin->flags.shaded) { + if (HAS_RESIZEBAR(wwin) && !wwin->flags.shaded) { /* Can't use wwin-frame->bottom_width because, in some cases (e.g. interactive placement), frame does not point to anything. */ bottom = RESIZEBAR_HEIGHT; @@ -640,9 +637,9 @@ typedef struct { #define WTOP(w) (w)->frame_y #define WLEFT(w) (w)->frame_x #define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \ - (HAS_BORDER(w) ? 2*FRAME_BORDER_WIDTH : 0)) + (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0)) #define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \ - (HAS_BORDER(w) ? 2*FRAME_BORDER_WIDTH : 0)) + (HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0)) static int compareWTop(const void *a, const void *b) @@ -900,9 +897,9 @@ initMoveData(WWindow *wwin, MoveData *data) data->calcY = wwin->frame_y; data->winWidth = wwin->frame->core->width + - (HAS_BORDER(wwin) ? 2*FRAME_BORDER_WIDTH : 0); + (HAS_BORDER_WITH_SELECT(wwin) ? 2*FRAME_BORDER_WIDTH : 0); data->winHeight = wwin->frame->core->height + - (HAS_BORDER(wwin) ? 2*FRAME_BORDER_WIDTH : 0); + (HAS_BORDER_WITH_SELECT(wwin) ? 2*FRAME_BORDER_WIDTH : 0); } @@ -1293,6 +1290,9 @@ updateWindowPosition(WWindow *wwin, MoveData *data, Bool doResistance, #define _KS KEY_CONTROL_WINDOW_WEIGHT +#define MOVABLE_BIT 0x01 +#define RESIZABLE_BIT 0x02 + int wKeyboardMoveResizeWindow(WWindow *wwin) { @@ -1309,15 +1309,24 @@ wKeyboardMoveResizeWindow(WWindow *wwin) int done,off_x,off_y,ww,wh; int kspeed = _KS; Time lastTime = 0; + KeyCode shiftl, shiftr, ctrll, ctrlmode; KeySym keysym=NoSymbol; int moment=0; - KeyCode shiftl,shiftr,ctrll,ctrlmode; + int modes = ((IS_MOVABLE(wwin) ? MOVABLE_BIT : 0) | + (IS_RESIZABLE(wwin) ? RESIZABLE_BIT : 0)); + int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1) + ? wGetHeadForWindow(wwin) + : scr->xine_info.primary_head); shiftl = XKeysymToKeycode(dpy, XK_Shift_L); shiftr = XKeysymToKeycode(dpy, XK_Shift_R); ctrll = XKeysymToKeycode(dpy, XK_Control_L); ctrlmode=done=off_x=off_y=0; + if (modes == RESIZABLE_BIT) { + ctrlmode = 1; + } + XSync(dpy, False); wusleep(10000); XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); @@ -1383,14 +1392,15 @@ wKeyboardMoveResizeWindow(WWindow *wwin) } if (kspeed < _KS) kspeed = _KS; lastTime = event.xkey.time; - - if (event.xkey.state & ControlMask && !wwin->flags.shaded) { - ctrlmode=1; - wUnselectWindows(scr); - } - else { - ctrlmode=0; - } + if (modes == (MOVABLE_BIT|RESIZABLE_BIT)) { + if ((event.xkey.state & ControlMask) && !wwin->flags.shaded) { + ctrlmode=1; + wUnselectWindows(scr); + } + else { + ctrlmode=0; + } + } if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) { if (ctrlmode) cycleGeometryDisplay(wwin, src_x+off_x, src_y+off_y, ww, wh, 0); @@ -1544,7 +1554,7 @@ wKeyboardMoveResizeWindow(WWindow *wwin) showGeometry(wwin, src_x+off_x, src_y+off_y, src_x+off_x+ww, src_y+off_y+wh,0); } else if(!scr->selected_windows) showPosition(wwin, src_x+off_x, src_y+off_y); - /**/ + if (done) { scr->keymove_tick=0; @@ -1599,6 +1609,17 @@ wKeyboardMoveResizeWindow(WWindow *wwin) wWindowChangeWorkspace(wwin, scr->current_workspace); wSetFocusTo(scr, wwin); } + + if (wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1 && + head != wGetHeadForWindow(wwin)) { + wArrangeIcons(scr, True); + } + + +#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP) + wWorkspaceResizeViewPort(scr, scr->current_workspace); +#endif + return 1; } } @@ -1638,12 +1659,15 @@ wMouseMoveWindow(WWindow *wwin, XEvent *ev) /* This needs not to change while moving, else bad things can happen */ int opaqueMove = wPreferences.opaque_move; MoveData moveData; + int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1) + ? wGetHeadForWindow(wwin) + : scr->xine_info.primary_head); #ifdef GHOST_WINDOW_MOVE - RImage *rimg; - - rimg = InitGhostWindowMove(scr); + RImage *rimg = InitGhostWindowMove(scr); #endif + if (!IS_MOVABLE(wwin)) + return False; if (wPreferences.opaque_move && !wPreferences.use_saveunders) { XSetWindowAttributes attr; @@ -1873,7 +1897,6 @@ wMouseMoveWindow(WWindow *wwin, XEvent *ev) if (wPreferences.opaque_move && !wPreferences.use_saveunders) { XSetWindowAttributes attr; - attr.save_under = False; XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr); @@ -1882,6 +1905,16 @@ wMouseMoveWindow(WWindow *wwin, XEvent *ev) freeMoveData(&moveData); + if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1 && + head != wGetHeadForWindow(wwin)) { + wArrangeIcons(scr, True); + } + +#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP) + if (started) + wWorkspaceResizeViewPort(scr, scr->current_workspace); +#endif + return started; } @@ -1964,6 +1997,12 @@ wMouseResizeWindow(WWindow *wwin, XEvent *ev) int orig_fy = fy; int orig_fw = fw; int orig_fh = fh; + int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr)>1) + ? wGetHeadForWindow(wwin) + : scr->xine_info.primary_head); + + if (!IS_RESIZABLE(wwin)) + return; if (wwin->flags.shaded) { wwarning("internal error: tryein"); @@ -1984,7 +2023,7 @@ wMouseResizeWindow(WWindow *wwin, XEvent *ev) ry2 = fy + fh - 1; shiftl = XKeysymToKeycode(dpy, XK_Shift_L); shiftr = XKeysymToKeycode(dpy, XK_Shift_R); - if (!WFLAGP(wwin, no_titlebar)) + if (HAS_TITLEBAR(wwin)) h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2; else h = 0; @@ -2165,6 +2204,15 @@ wMouseResizeWindow(WWindow *wwin, XEvent *ev) WMHandleEvent(&event); } } + + if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && + head != wGetHeadForWindow(wwin)) { + wArrangeIcons(scr, True); + } + +#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP) + wWorkspaceResizeViewPort(scr, scr->current_workspace); +#endif } #undef LEFT @@ -2316,11 +2364,11 @@ InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret, *y_ret = 0; return; } - if (!WFLAGP(wwin, no_titlebar)) { + if (HAS_TITLEBAR(wwin)) { h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2; height += h; } - if (!WFLAGP(wwin, no_resizebar)) { + if (HAS_RESIZEBAR(wwin)) { height += RESIZEBAR_HEIGHT; } XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); diff --git a/src/placement.c b/src/placement.c index f5c0b529..47a1af6a 100644 --- a/src/placement.c +++ b/src/placement.c @@ -349,33 +349,32 @@ smartPlaceWindow(WWindow *wwin, int *x_ret, int *y_ret, unsigned int width, unsigned int height, WArea usableArea) { - WScreen *scr = wwin->screen_ptr; + //WScreen *scr = wwin->screen_ptr; int test_x = 0, test_y = Y_ORIGIN(scr); int from_x, to_x, from_y, to_y; int sx; int min_isect, min_isect_x, min_isect_y; int sum_isect; - int extra_height; - - if (wwin->frame) - extra_height = wwin->frame->top_width + wwin->frame->bottom_width; - else - extra_height = 24; /* random value */ + if (wwin->frame) { + height += wwin->frame->top_width + wwin->frame->bottom_width; + } else { + if (HAS_TITLEBAR(wwin)) height += 18; + if (HAS_RESIZEBAR(wwin)) height += 8; + } + if (HAS_BORDER(wwin)) { + height += 2; + width += 2; + } sx = X_ORIGIN(scr); min_isect = INT_MAX; min_isect_x = sx; min_isect_y = test_y; - height += extra_height; - while (((test_y + height) < usableArea.y2)) { - test_x = sx; - while ((test_x + width) < usableArea.x2) { - sum_isect = calcSumOfCoveredAreas(wwin, test_x, test_y, width, height); @@ -430,21 +429,23 @@ autoPlaceWindow(WWindow *wwin, int *x_ret, int *y_ret, int loc_ok = False, tw,tx,ty,th; int swidth, sx; WWindow *test_window; - int extra_height; - - if (wwin->frame) - extra_height = wwin->frame->top_width + wwin->frame->bottom_width + 2; - else - extra_height = 24; /* random value */ + if (wwin->frame) { + height += wwin->frame->top_width + wwin->frame->bottom_width; + } else { + if (HAS_TITLEBAR(wwin)) height += 18; + if (HAS_RESIZEBAR(wwin)) height += 8; + } + if (HAS_BORDER(wwin)) { + height += 2; + width += 2; + } swidth = usableArea.x2-usableArea.x1; sx = X_ORIGIN(scr); /* this was based on fvwm2's smart placement */ - height += extra_height; - while (((test_y + height) < (usableArea.y2 - usableArea.y1)) && !loc_ok) { test_x = sx; @@ -539,17 +540,19 @@ cascadeWindow(WScreen *scr, WWindow *wwin, int *x_ret, int *y_ret, unsigned int width, unsigned int height, int h, WArea usableArea) { - unsigned int extra_height; - - - if (wwin->frame) - extra_height = wwin->frame->top_width + wwin->frame->bottom_width; - else - extra_height = 24; /* random value */ + if (wwin->frame) { + height += wwin->frame->top_width + wwin->frame->bottom_width; + } else { + if (HAS_TITLEBAR(wwin)) height += 18; + if (HAS_RESIZEBAR(wwin)) height += 8; + } + if (HAS_BORDER(wwin)) { + height += 2; + width += 2; + } *x_ret = h * scr->cascade_index + X_ORIGIN(scr); *y_ret = h * scr->cascade_index + Y_ORIGIN(scr); - height += extra_height; if (width + *x_ret > usableArea.x2 || height + *y_ret > usableArea.y2) { scr->cascade_index = 0; @@ -564,15 +567,21 @@ randomPlaceWindow(WScreen *scr, WWindow *wwin, int *x_ret, int *y_ret, unsigned int width, unsigned int height, WArea usableArea) { - int w, h, extra_height; + int w, h; - if (wwin->frame) - extra_height = wwin->frame->top_width + wwin->frame->bottom_width + 2; - else - extra_height = 24; /* random value */ + if (wwin->frame) { + height += wwin->frame->top_width + wwin->frame->bottom_width; + } else { + if (HAS_TITLEBAR(wwin)) height += 18; + if (HAS_RESIZEBAR(wwin)) height += 8; + } + if (HAS_BORDER(wwin)) { + height += 2; + width += 2; + } w = ((usableArea.x2-X_ORIGIN(scr)) - width); - h = ((usableArea.y2-Y_ORIGIN(scr)) - height - extra_height); + h = ((usableArea.y2-Y_ORIGIN(scr)) - height); if (w<1) w = 1; if (h<1) h = 1; *x_ret = X_ORIGIN(scr) + rand()%w; diff --git a/src/screen.c b/src/screen.c index 8e619f4a..62cd0e7a 100644 --- a/src/screen.c +++ b/src/screen.c @@ -62,6 +62,9 @@ #ifdef OLWM_HINTS # include "openlook.h" #endif +#ifdef NETWM_HINTS +# include "wmspec.h" +#endif #include "xinerama.h" @@ -787,6 +790,10 @@ wScreenInit(int screen_number) wOLWMInitStuff(scr); #endif +#ifdef NETWM_HINTS + wNETWMInitStuff(scr); +#endif + /* create initial workspace */ wWorkspaceNew(scr); @@ -1014,10 +1021,21 @@ wScreenUpdateUsableArea(WScreen *scr) } } -#ifdef KWM_HINTS +#ifdef NETWM_HINTS { WArea area; + if (wNETWMGetUsableArea(scr, &area)) { + scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1); + scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1); + scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2); + scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2); + } + } +#endif +#ifdef KWM_HINTS + { + WArea area; if (wKWMGetUsableArea(scr, &area)) { scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1); scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1); @@ -1094,6 +1112,10 @@ wScreenUpdateUsableArea(WScreen *scr) #endif #endif +#ifdef NETWM_HINTS + wNETWMUpdateWorkarea(scr); +#endif + { unsigned size = wPreferences.workspace_border_size; unsigned position = wPreferences.workspace_border_position; @@ -1146,7 +1168,16 @@ wScreenRestoreState(WScreen *scr) wfree(path); } - if (!wPreferences.flags.noclip && scr->session_state) { + if (!scr->session_state) { + scr->session_state = WMCreatePLDictionary(NULL, NULL); + } + + if (!wPreferences.flags.nodock) { + state = WMGetFromPLDictionary(scr->session_state, dDock); + scr->dock = wDockRestoreState(scr, state, WM_DOCK); + } + + if (!wPreferences.flags.noclip) { state = WMGetFromPLDictionary(scr->session_state, dClip); scr->clip_icon = wClipRestoreState(scr, state); } @@ -1154,17 +1185,10 @@ wScreenRestoreState(WScreen *scr) wWorkspaceRestoreState(scr); #ifdef VIRTUAL_DESKTOP - /* - * * create inputonly windows at the border of screen - * */ - wWorkspaceManageEdge(scr); + /* create inputonly windows at the border of screen */ + wWorkspaceManageEdge(scr); #endif - if (!wPreferences.flags.nodock && scr->session_state) { - state = WMGetFromPLDictionary(scr->session_state, dDock); - scr->dock = wDockRestoreState(scr, state, WM_DOCK); - } - wScreenUpdateUsableArea(scr); } @@ -1201,7 +1225,7 @@ wScreenSaveState(WScreen *scr) old_state = scr->session_state; - scr->session_state = WMCreatePLDictionary(NULL, NULL, NULL); + scr->session_state = WMCreatePLDictionary(NULL, NULL); WMPLSetCaseSensitive(True); @@ -1239,9 +1263,9 @@ wScreenSaveState(WScreen *scr) wMenuSaveState(scr); - if (wScreenCount == 1) + if (wScreenCount == 1) { str = wdefaultspathfordomain("WMState"); - else { + } else { char buf[16]; snprintf(buf, sizeof(buf), "WMState.%i", scr->screen); str = wdefaultspathfordomain(buf); diff --git a/src/screen.h b/src/screen.h index 1ae1971a..12514099 100644 --- a/src/screen.h +++ b/src/screen.h @@ -77,10 +77,8 @@ typedef struct _WScreen { int scr_height; #ifdef VIRTUAL_DESKTOP - Window virtual_edge_u; - Window virtual_edge_d; - Window virtual_edge_l; - Window virtual_edge_r; + int virtual_nr_edges; + Window * virtual_edges; #endif Window root_win; /* root window of screen */ @@ -328,6 +326,7 @@ typedef struct _WScreen { unsigned int colormap_stuff_blocked:1; unsigned int doing_alt_tab:1; unsigned int jump_back_pending:1; + unsigned int ignore_focus_events:1; #ifdef KWM_HINTS unsigned int kwm_syncing_name:1; unsigned int kwm_syncing_count:1; diff --git a/src/session.c b/src/session.c index d9a834ff..7020f6c5 100644 --- a/src/session.c +++ b/src/session.c @@ -211,8 +211,6 @@ makeWindowState(WWindow *wwin, WApplication *wapp) { WScreen *scr = wwin->screen_ptr; Window win; - int argc; - char **argv; int i; unsigned mask; char *class, *instance, *command=NULL, buffer[512]; @@ -225,10 +223,7 @@ makeWindowState(WWindow *wwin, WApplication *wapp) else win = wwin->client_win; - if (XGetCommand(dpy, win, &argv, &argc) && argc>0) { - command = wtokenjoin(argv, argc); - XFreeStringList(argv); - } + command = GetCommandForWindow(win); if (!command) return NULL; @@ -266,14 +261,14 @@ makeWindowState(WWindow *wwin, WApplication *wapp) shortcut = WMCreatePLString(buffer); win_state = WMCreatePLDictionary(sName, name, - sCommand, cmd, - sWorkspace, workspace, - sShaded, shaded, - sMiniaturized, miniaturized, - sHidden, hidden, - sShortcutMask, shortcut, - sGeometry, geometry, - NULL); + sCommand, cmd, + sWorkspace, workspace, + sShaded, shaded, + sMiniaturized, miniaturized, + sHidden, hidden, + sShortcutMask, shortcut, + sGeometry, geometry, + NULL); WMReleasePropList(name); WMReleasePropList(cmd); @@ -321,7 +316,7 @@ wSessionSaveState(WScreen *scr) make_keys(); if (!scr->session_state) { - scr->session_state = WMCreatePLDictionary(NULL, NULL, NULL); + scr->session_state = WMCreatePLDictionary(NULL, NULL); if (!scr->session_state) return; } @@ -1072,9 +1067,9 @@ smSaveYourselfPhase2Proc(SmcConn smc_conn, SmPointer client_data) } plState = WMCreatePLDictionary(WMCreatePLString("Version"), - WMCreatePLString("1.0"), - WMCreatePLString("Screens"), - state, NULL); + WMCreatePLString("1.0"), + WMCreatePLString("Screens"), + state, NULL); WMWritePropListToFile(plState, statefile, False); diff --git a/src/stacking.c b/src/stacking.c index e246983f..104b2a0e 100644 --- a/src/stacking.c +++ b/src/stacking.c @@ -35,6 +35,7 @@ #include "actions.h" #include "properties.h" #include "stacking.h" +#include "workspace.h" /*** Global Variables ***/ @@ -152,6 +153,9 @@ CommitStacking(WScreen *scr) XRestackWindows(dpy, windows, i); wfree(windows); +#ifdef VIRTUAL_DESKTOP + wWorkspaceRaiseEdge(scr); +#endif WMPostNotificationName(WMNResetStacking, scr, NULL); } @@ -376,6 +380,10 @@ wLowerFrame(WCoreWindow *frame) } notifyStackChange(frame, "lower"); + +#ifdef VIRTUAL_DESKTOP + wWorkspaceRaiseEdge(scr); +#endif } @@ -510,6 +518,10 @@ MoveInStackListAbove(WCoreWindow *next, WCoreWindow *frame) } WMPostNotificationName(WMNResetStacking, scr, NULL); + +#ifdef VIRTUAL_DESKTOP + wWorkspaceRaiseEdge(scr); +#endif } diff --git a/src/startup.c b/src/startup.c index 3eb6faf9..6d155f2e 100644 --- a/src/startup.c +++ b/src/startup.c @@ -111,6 +111,7 @@ extern int wXkbEventBase; extern XContext wWinContext; extern XContext wAppWinContext; extern XContext wStackContext; +extern XContext wVEdgeContext; /* atoms */ extern Atom _XA_WM_STATE; @@ -756,6 +757,7 @@ StartUp(Bool defaultScreenOnly) wWinContext = XUniqueContext(); wAppWinContext = XUniqueContext(); wStackContext = XUniqueContext(); + wVEdgeContext = XUniqueContext(); /* _XA_VERSION = XInternAtom(dpy, "VERSION", False);*/ @@ -820,6 +822,17 @@ StartUp(Bool defaultScreenOnly) wCursor[WCUR_QUESTION] = XCreateFontCursor(dpy, XC_question_arrow); wCursor[WCUR_TEXT] = XCreateFontCursor(dpy, XC_xterm); /* odd name???*/ wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross); + { + Pixmap cur = XCreatePixmap(dpy, DefaultRootWindow(dpy), 16, 16, 1); + GC gc = XCreateGC(dpy, cur, 0, NULL); + XColor black; + memset(&black, 0, sizeof(XColor)); + XSetForeground(dpy, gc, 0); + XFillRectangle(dpy, cur, gc, 0, 0, 16, 16); + XFreeGC(dpy, gc); + wCursor[WCUR_EMPTY] = XCreatePixmapCursor(dpy, cur, cur, &black, &black, 0, 0); + XFreePixmap(dpy, cur); + } /* signal handler stuff that gets called when a signal is caught */ WMAddPersistentTimerHandler(500, delayedAction, NULL); @@ -1119,7 +1132,7 @@ manageAllWindows(WScreen *scr, int crashRecovery) if (crashRecovery) { int border; - border = (WFLAGP(wwin, no_border) ? 0 : FRAME_BORDER_WIDTH); + border = (!HAS_BORDER(wwin) ? 0 : FRAME_BORDER_WIDTH); wWindowMove(wwin, wwin->frame_x - border, wwin->frame_y - border - diff --git a/src/text.c b/src/text.c index 58889306..c483d640 100644 --- a/src/text.c +++ b/src/text.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "WindowMaker.h" @@ -42,14 +43,14 @@ #endif -#if 0 +#ifdef DEBUG # define ENTER(X) fprintf(stderr,"Entering: %s()\n", X); # define LEAVE(X) fprintf(stderr,"Leaving: %s()\n", X); -# define DEBUG(X) fprintf(stderr,"debug: %s()\n", X); +# define PDEBUG(X) fprintf(stderr,"debug: %s()\n", X); #else # define ENTER(X) # define LEAVE(X) -# define DEBUG(X) +# define PDEBUG(X) #endif extern Cursor wCursor[WCUR_LAST]; @@ -582,32 +583,32 @@ textEventHandler( WObjDescriptor *desc, XEvent *event ) * text so we can wTextRefresh() */ if( event->xmotion.state & (Button1Mask|Button3Mask|Button2Mask) ) { - DEBUG("MotionNotify"); + PDEBUG("MotionNotify"); handled = True; wtext->text.endPos = textXtoPos( wtext, event->xmotion.x ); } break; case ButtonPress: - DEBUG("ButtonPress"); + PDEBUG("ButtonPress"); handled = True; wtext->text.startPos = textXtoPos( wtext, event->xbutton.x ); wtext->text.endPos = wtext->text.startPos; break; case ButtonRelease: - DEBUG("ButtonRelease"); + PDEBUG("ButtonRelease"); handled = True; wtext->text.endPos = textXtoPos( wtext, event->xbutton.x ); break; case KeyPress: - DEBUG("KeyPress"); + PDEBUG("KeyPress"); handled = handleKeyPress( wtext, &event->xkey ); break; case EnterNotify: - DEBUG("EnterNotify"); + PDEBUG("EnterNotify"); handled = True; #if 0 if (!wtext->magic) @@ -621,7 +622,7 @@ textEventHandler( WObjDescriptor *desc, XEvent *event ) break; case LeaveNotify: - DEBUG("LeaveNotify"); + PDEBUG("LeaveNotify"); handled = True; #if 0 wtext->blinking = 0; diff --git a/src/wdefaults.c b/src/wdefaults.c index 23f6ac58..7a481c8d 100644 --- a/src/wdefaults.c +++ b/src/wdefaults.c @@ -500,7 +500,7 @@ wDefaultChangeIcon(WScreen *scr, char *instance, char* class, char *file) int same = 0; if (!dict) { - dict = WMCreatePLDictionary(NULL, NULL, NULL); + dict = WMCreatePLDictionary(NULL, NULL); if (dict) { db->dictionary = dict; } else { diff --git a/src/window.c b/src/window.c index 9876b1af..9cc51af9 100644 --- a/src/window.c +++ b/src/window.c @@ -1,9 +1,9 @@ /* window.c - client window managing stuffs - * + * * Window Maker window manager - * + * * Copyright (c) 1997-2003 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 @@ -16,7 +16,7 @@ * * 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, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ @@ -27,8 +27,8 @@ #ifdef SHAPE #include #endif -#ifdef KEEP_XKB_LOCK_STATUS -#include +#ifdef KEEP_XKB_LOCK_STATUS +#include #endif /* KEEP_XKB_LOCK_STATUS */ #include #include @@ -68,6 +68,9 @@ #ifdef OLWM_HINTS # include "openlook.h" #endif +#ifdef NETWM_HINTS +# include "wmspec.h" +#endif /****** Global Variables ******/ @@ -154,7 +157,7 @@ appearanceObserver(void *self, WMNotification *notif) wFrameWindowResize(wwin->frame, wwin->frame->core->width, wwin->frame->top_width - 1); - wwin->client.y = wwin->frame_y - wwin->client.height + wwin->client.y = wwin->frame_y - wwin->client.height + wwin->frame->top_width; wWindowSynthConfigureNotify(wwin); } @@ -199,7 +202,7 @@ WWindow* wWindowCreate() { WWindow *wwin; - + wwin = wmalloc(sizeof(WWindow)); wretain(wwin); @@ -222,9 +225,9 @@ wWindowDestroy(WWindow *wwin) if (wwin->screen_ptr->cmap_window == wwin) { wwin->screen_ptr->cmap_window = NULL; } - + WMRemoveNotificationObserver(wwin); - + wwin->flags.destroyed = 1; for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) { @@ -278,10 +281,14 @@ wWindowDestroy(WWindow *wwin) if (wPreferences.auto_arrange_icons) wArrangeIcons(wwin->screen_ptr, True); } - wrelease(wwin); -} +#ifdef NETWM_HINTS + if (wwin->net_icon_image) + RReleaseImage(wwin->net_icon_image); +#endif + wrelease(wwin); +} static void @@ -307,7 +314,7 @@ setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints) wwin->client_flags.no_miniaturize_button = ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1); - wwin->client_flags.no_miniaturizable = + wwin->client_flags.no_miniaturizable = wwin->client_flags.no_miniaturize_button; wwin->client_flags.no_resizebar = @@ -322,7 +329,7 @@ setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints) WMMiniaturizableWindowMask)) { wwin->client_flags.no_titlebar = 0; } else { - wwin->client_flags.no_titlebar = + wwin->client_flags.no_titlebar = ((gs_hints->window_style & WMTitledWindowMask)?0:1); } @@ -356,11 +363,11 @@ wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags, if (wapp && !wapp->flags.emulated) wflags->emulate_appicon = 0; } - - if (wwin->transient_for!=None + + if (wwin->transient_for!=None && wwin->transient_for!=wwin->screen_ptr->root_win) wflags->emulate_appicon = 0; - + if (wflags->sunken && mask->sunken && wflags->floating && mask->floating) wflags->sunken = 0; } @@ -381,7 +388,7 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) * - guess some settings * - use GNUstep/external window attributes * - set hints specified for the app in the resource DB - * + * */ WSETUFLAG(wwin, broken_close, 0); @@ -403,7 +410,7 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) WSETUFLAG(wwin, no_resizable, 1); WSETUFLAG(wwin, no_resizebar, 1); } - + /* set GNUstep window attributes */ if (wwin->wm_gnustep_attr) { setupGNUstepHints(wwin, wwin->wm_gnustep_attr); @@ -424,20 +431,26 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) int tmp_workspace = -1; int tmp_level = INT_MIN; /* INT_MIN is never used by the window levels */ Bool check; - + check = False; - + #ifdef MWM_HINTS wMWMCheckClientHints(wwin); #endif /* MWM_HINTS */ +#ifdef NETWM_HINTS + if (!check) + check = wNETWMCheckClientHints(wwin, &tmp_level, &tmp_workspace); +#endif + #ifdef GNOME_STUFF - check = wGNOMECheckClientHints(wwin, &tmp_level, &tmp_workspace); + if (!check) + check = wGNOMECheckClientHints(wwin, &tmp_level, &tmp_workspace); #endif /* GNOME_STUFF */ - + #ifdef KWM_HINTS if (!check) - wKWMCheckClientHints(wwin, &tmp_level, &tmp_workspace); + check = wKWMCheckClientHints(wwin, &tmp_level, &tmp_workspace); #endif /* KWM_HINTS */ #ifdef OLWM_HINTS @@ -458,6 +471,14 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) *level = tmp_level; } + if (wwin->transient_for!=None && wwin->transient_for != scr->root_win) { + WWindow * transientOwner = wWindowFor(wwin->transient_for); + if (transientOwner) { + int ownerLevel = transientOwner->frame->core->stacking->window_level; + if (ownerLevel > *level) *level = ownerLevel; + } + } + if (tmp_workspace >= 0) { *workspace = tmp_workspace % scr->workspace_count; } @@ -467,7 +488,7 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) * Set attributes specified only for that window/class. * This might do duplicate work with the 1st wDefaultFillAttributes(). */ - wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class, + wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class, &wwin->user_flags, &wwin->defined_user_flags, False); /* @@ -491,8 +512,8 @@ wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace) wwin->user_flags.sunken = 0; WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar)); - - + + /* windows that have takefocus=False shouldn't take focus at all */ if (wwin->focus_mode == WFM_NO_INPUT) { wwin->client_flags.no_focusable = 1; @@ -541,6 +562,78 @@ wWindowObscuresWindow(WWindow *wwin, WWindow *obscured) } +static void +fixLeaderProperties(WWindow *wwin) +{ + XClassHint *classHint; + XWMHints *hints, *clientHints; + Window leaders[2], window; + char **argv, *command; + int argc, i, pid; + Bool haveCommand; + + classHint = XAllocClassHint(); + clientHints = XGetWMHints(dpy, wwin->client_win); + pid = GetPidForWindow(wwin->client_win); + if (pid > 0) { + haveCommand = GetCommandForPid(pid, &argv, &argc); + } else { + haveCommand = False; + } + + leaders[0] = wwin->client_leader; + leaders[1] = wwin->group_id; + + if (haveCommand) { + command = GetCommandForWindow(wwin->client_win); + if (command) { + /* command already set. nothing to do. */ + wfree(command); + } else { + XSetCommand(dpy, wwin->client_win, argv, argc); + } + } + + for (i=0; i<2; i++) { + window = leaders[i]; + if (window) { + if (XGetClassHint(dpy, window, classHint) == 0) { + classHint->res_name = wwin->wm_instance; + classHint->res_class = wwin->wm_class; + XSetClassHint(dpy, window, classHint); + } + hints = XGetWMHints(dpy, window); + if (hints) { + XFree(hints); + } else if (clientHints) { + /* set window group leader to self */ + clientHints->window_group = window; + clientHints->flags |= WindowGroupHint; + XSetWMHints(dpy, window, clientHints); + } + + if (haveCommand) { + command = GetCommandForWindow(window); + if (command) { + /* command already set. nothing to do. */ + wfree(command); + } else { + XSetCommand(dpy, window, argv, argc); + } + } + } + } + + XFree(classHint); + if (clientHints) { + XFree(clientHints); + } + if (haveCommand) { + wfree(argv); + } +} + + static Window createFakeWindowGroupLeader(WScreen *scr, Window win, char *instance, char *class) { @@ -592,24 +685,24 @@ matchIdentifier(void *item, void *cdata) * reparents the window and allocates a descriptor for it. * Window manager hints and other hints are fetched to configure * the window decoration attributes and others. User preferences - * for the window are used if available, to configure window + * for the window are used if available, to configure window * decorations and some behaviour. * If in startup, windows that are override redirect, * unmapped and never were managed and are Withdrawn are not * managed. - * + * * Returns: * the new window descriptor - * + * * Side effects: * The window is reparented and appropriate notification * is done to the client. Input mask for the window is setup. - * The window descriptor is also associated with various window + * The window descriptor is also associated with various window * contexts and inserted in the head of the window list. - * Event handler contexts are associated for some objects + * Event handler contexts are associated for some objects * (buttons, titlebar and resizebar) - * - *---------------------------------------------------------------- + * + *---------------------------------------------------------------- */ WWindow* wManageWindow(WScreen *scr, Window window) @@ -617,7 +710,7 @@ wManageWindow(WScreen *scr, Window window) WWindow *wwin; int x, y; unsigned width, height; - XWindowAttributes wattribs; + XWindowAttributes wattribs; XSetWindowAttributes attribs; WWindowState *win_state; WWindow *transientOwner = NULL; @@ -678,20 +771,20 @@ wManageWindow(WScreen *scr, Window window) int junk; unsigned int ujunk; int b_shaped; - + XShapeSelectInput(dpy, window, ShapeNotifyMask); - XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk, + XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk, &ujunk, &junk, &junk, &junk, &ujunk, &ujunk); wwin->flags.shaped = b_shaped; } #endif - + /* *-------------------------------------------------- - * + * * Get hints and other information in properties * - *-------------------------------------------------- + *-------------------------------------------------- */ PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance); @@ -706,7 +799,7 @@ wManageWindow(WScreen *scr, Window window) attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; attribs.save_under = False; XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate - |CWSaveUnder, &attribs); + |CWSaveUnder, &attribs); XSetWindowBorderWidth(dpy, window, 0); /* get hints from GNUstep app */ @@ -780,10 +873,10 @@ wManageWindow(WScreen *scr, Window window) /* *-------------------------------------------------- - * + * * Setup the decoration/window attributes and * geometry - * + * *-------------------------------------------------- */ @@ -812,6 +905,8 @@ wManageWindow(WScreen *scr, Window window) wwin->main_window = wwin->client_win; } + fixLeaderProperties(wwin); + wwin->orig_main_window = wwin->main_window; if (wwin->flags.is_gnustep) { @@ -835,7 +930,7 @@ wManageWindow(WScreen *scr, Window window) #define ADEQUATE(x) ((x)!=None && (x)!=wwin->client_win && (x)!=fPtr->leader) - + // only enter here if PropGetWMClass() succeds PropGetWMClass(wwin->main_window, &class, &instance); buffer = StrConcatDot(instance, class); @@ -924,20 +1019,26 @@ wManageWindow(WScreen *scr, Window window) wwin->flags.miniaturized = 1; } - if (WFLAGP(wwin, start_maximized) && !WFLAGP(wwin, no_resizable)) { + if (WFLAGP(wwin, start_maximized) && IS_RESIZABLE(wwin)) { wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL; } { - Bool bla; - - bla = False; +#if defined(NETWM_HINTS) || defined(GNOME_STUFF) || defined(KWM_HINTS) + Bool bla = False; +#endif + +#ifdef NETWM_HINTS + if (!bla) + bla = wNETWMCheckInitialClientState(wwin); +#endif #ifdef GNOME_STUFF - bla = wGNOMECheckInitialClientState(wwin); + if (!bla) + bla = wGNOMECheckInitialClientState(wwin); #endif #ifdef KWM_HINTS if (!bla) - wKWMCheckClientInitialState(wwin); + bla = wKWMCheckClientInitialState(wwin); #endif } @@ -989,7 +1090,7 @@ wManageWindow(WScreen *scr, Window window) } } - /* if we're restarting, restore saved state (from hints). + /* if we're restarting, restore saved state (from hints). * This will overwrite previous */ { WSavedState *wstate; @@ -1017,7 +1118,7 @@ wManageWindow(WScreen *scr, Window window) if (win_state != NULL) mask = win_state->state->window_shortcuts; - + if (wstate != NULL && mask == 0) mask = wstate->window_shortcuts; @@ -1047,7 +1148,7 @@ wManageWindow(WScreen *scr, Window window) wwin->wm_hints->initial_state = NormalState; } - /* set workspace on which the window starts */ + /* set workspace on which the window starts */ if (workspace >= 0) { if (workspace > scr->workspace_count-1) { workspace = workspace % scr->workspace_count; @@ -1092,18 +1193,18 @@ wManageWindow(WScreen *scr, Window window) y = win_state->state->y; } else if ((wwin->transient_for==None || wPreferences.window_placement!=WPM_MANUAL) - && !scr->flags.startup + && !scr->flags.startup && workspace == scr->current_workspace && !wwin->flags.miniaturized && !wwin->flags.maximized && !(wwin->normal_hints->flags & (USPosition|PPosition))) { - + if (transientOwner && transientOwner->flags.mapped) { int offs = WMAX(20, 2*transientOwner->frame->top_width); WMRect rect; int head; - - x = transientOwner->frame_x + + + x = transientOwner->frame_x + abs((transientOwner->frame->core->width - width)/2) + offs; y = transientOwner->frame_y + abs((transientOwner->frame->core->height - height)/3) + offs; @@ -1115,15 +1216,15 @@ wManageWindow(WScreen *scr, Window window) rect.pos.y = transientOwner->frame_y; rect.size.width = transientOwner->frame->core->width; rect.size.height = transientOwner->frame->core->height; - + head = wGetHeadForRect(scr, rect); rect = wGetRectForHead(scr, head); - + if (x < rect.pos.x) x = rect.pos.x; else if (x + width > rect.pos.x + rect.size.width) x = rect.pos.x + rect.size.width - width; - + if (y < rect.pos.y) y = rect.pos.y; else if (y + height > rect.pos.y + rect.size.height) @@ -1140,14 +1241,14 @@ wManageWindow(WScreen *scr, Window window) int head, flags; WMRect rect; int reposition = 0; - + /* * Make spash screens come out in the center of a head * trouble is that most splashies never get here * they are managed trough atoms but god knows where. - * Dan, do you know ? - * - * Most of them are not managed, they are set + * Dan, do you know ? -peter + * + * Most of them are not managed, they have set * OverrideRedirect, which means we can't do anything about * them. -alfredo */ @@ -1160,7 +1261,7 @@ wManageWindow(WScreen *scr, Window window) reposition = 1; - } else + } else #endif { /* @@ -1179,31 +1280,31 @@ wManageWindow(WScreen *scr, Window window) if (flags & XFLAG_MULTIPLE) reposition = 2; } - + switch (reposition) { case 1: head = wGetHeadForPointerLocation(scr); rect = wGetRectForHead(scr, head); - + x = rect.pos.x + (x * rect.size.width)/scr->scr_width; y = rect.pos.y + (y * rect.size.height)/scr->scr_height; break; - + case 2: rect = wGetRectForHead(scr, head); - + if (x < rect.pos.x) x = rect.pos.x; else if (x + width > rect.pos.x + rect.size.width) x = rect.pos.x + rect.size.width - width; - + if (y < rect.pos.y) y = rect.pos.y; else if (y + height > rect.pos.y + rect.size.height) y = rect.pos.y + rect.size.height - height; - + break; - + default: break; } @@ -1213,6 +1314,10 @@ wManageWindow(WScreen *scr, Window window) wScreenBringInside(scr, &x, &y, width, height); } +#ifdef NETWM_HINTS + wNETWMPositionSplash(wwin, &x, &y, width, height); +#endif + if (wwin->flags.urgent) { if (!IS_OMNIPRESENT(wwin)) wwin->flags.omnipresent ^= 1; @@ -1220,7 +1325,7 @@ wManageWindow(WScreen *scr, Window window) /* *-------------------------------------------------- - * + * * Create frame, borders and do reparenting * *-------------------------------------------------- @@ -1230,14 +1335,14 @@ wManageWindow(WScreen *scr, Window window) if (wPreferences.modelock) foo |= WFF_LANGUAGE_BUTTON; #endif - if (!WFLAGP(wwin, no_titlebar)) + if (HAS_TITLEBAR(wwin)) foo |= WFF_TITLEBAR; - if (!WFLAGP(wwin, no_resizebar)) + if (HAS_RESIZEBAR(wwin)) foo |= WFF_RESIZEBAR; - if (!WFLAGP(wwin, no_border)) + if (HAS_BORDER(wwin)) foo |= WFF_BORDER; - wwin->frame = wFrameWindowCreate(scr, window_level, + wwin->frame = wFrameWindowCreate(scr, window_level, x, y, width, height, &wPreferences.window_title_clearance, foo, scr->window_title_texture, @@ -1312,7 +1417,7 @@ wManageWindow(WScreen *scr, Window window) y -= wwin->frame->top_width + wwin->frame->bottom_width; } - /* + /* * wWindowConfigure() will init the client window's size * (wwin->client.{width,height}) and all other geometry * related variables (frame_x,frame_y) @@ -1324,7 +1429,7 @@ wManageWindow(WScreen *scr, Window window) /* *-------------------------------------------------- - * + * * Setup descriptors and save window to internal * lists * @@ -1342,12 +1447,10 @@ wManageWindow(WScreen *scr, Window window) if (leader && leader->main_window==None) { leader->main_window = leader->client_win; } - app = wApplicationCreate(scr, wwin->main_window); + app = wApplicationCreate(wwin); if (app) { app->last_workspace = workspace; - app->main_window_desc->fake_group = wwin->fake_group; - /* * Do application specific stuff, like setting application * wide attributes. @@ -1416,10 +1519,10 @@ wManageWindow(WScreen *scr, Window window) if (wPreferences.superfluous && !wPreferences.no_animations && !scr->flags.startup && (wwin->transient_for==None || wwin->transient_for==scr->root_win) - /* + /* * The brain damaged idiotic non-click to focus modes will * have trouble with this because: - * + * * 1. window is created and mapped by the client * 2. window is mapped by wmaker in small size * 3. window is animated to grow to normal size @@ -1427,7 +1530,7 @@ wManageWindow(WScreen *scr, Window window) * 5. eventually, the EnterNotify event that would trigger * the window focusing (if the mouse is over that window) * will be processed by wmaker. - * But since this event will be rather delayed + * But since this event will be rather delayed * (step 3 has a large delay) the time when the event ocurred * and when it is processed, the client that owns that window * will reject the XSetInputFocus() for it. @@ -1474,7 +1577,7 @@ wManageWindow(WScreen *scr, Window window) /* Update name must come after WApplication stuff is done */ wWindowUpdateName(wwin, title); if (title) - XFree(title); + XFree(title); XUngrabServer(dpy); @@ -1507,7 +1610,7 @@ wManageWindow(WScreen *scr, Window window) wColormapInstallForWindow(scr, scr->cmap_window); - + #ifdef OLWM_HINTS if (wwin->client_flags.olwm_warp_to_pin && wwin->frame->titlebar != NULL && !WFLAGP(wwin, no_close_button) && !withdraw) { @@ -1526,10 +1629,10 @@ wManageWindow(WScreen *scr, Window window) WMAddNotificationObserver(appearanceObserver, wwin, WNWindowAppearanceSettingsChanged, wwin); - + /* *-------------------------------------------------- - * + * * Cleanup temporary stuff * *-------------------------------------------------- @@ -1574,21 +1677,21 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, WSETUFLAG(wwin, no_miniaturizable, 1); wwin->focus_mode = WFM_PASSIVE; - + wwin->client_win = window; wwin->screen_ptr = scr; wwin->transient_for = owner; - + wwin->client.x = x; wwin->client.y = y; wwin->client.width = width; wwin->client.height = height; - + wwin->frame_x = wwin->client.x; wwin->frame_y = wwin->client.y; - + foo = WFF_RIGHT_BUTTON|WFF_BORDER; foo |= WFF_TITLEBAR; #ifdef XKB_BUTTON_HINT @@ -1603,7 +1706,7 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, scr->resizebar_texture, scr->window_title_color, &scr->title_font); - + XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor); wwin->frame->flags.is_client_window_frame = 1; @@ -1616,28 +1719,28 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, /* hide buttons */ wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON); - + wwin->frame->child = wwin; - + wwin->frame->workspace = wwin->screen_ptr->current_workspace; - + #ifdef XKB_BUTTON_HINT if (wPreferences.modelock) wwin->frame->on_click_language = windowLanguageClick; #endif - + wwin->frame->on_click_right = windowCloseClick; - + wwin->frame->on_mousedown_titlebar = titlebarMouseDown; wwin->frame->on_dblclick_titlebar = titlebarDblClick; - + wwin->frame->on_mousedown_resizebar = resizebarMouseDown; wwin->client.y += wwin->frame->top_width; - XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window, + XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window, 0, wwin->frame->top_width); - wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y, + wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y, wwin->client.width, wwin->client.height); /* setup the frame descriptor */ @@ -1648,7 +1751,7 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, XLowerWindow(dpy, window); XMapSubwindows(dpy, wwin->frame->core->window); - + /* setup stacking descriptor */ if (wwin->transient_for!=None && wwin->transient_for!=scr->root_win) { WWindow *tmp; @@ -1658,7 +1761,7 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, } else { wwin->frame->core->stacking->child_of = NULL; } - + if (!scr->focused_window) { /* first window on the list */ @@ -1692,17 +1795,17 @@ wManageInternalWindow(WScreen *scr, Window window, Window owner, /* - *---------------------------------------------------------------------- + *---------------------------------------------------------------------- * wUnmanageWindow-- * Removes the frame window from a window and destroys all data * related to it. The window will be reparented back to the root window * if restore is True. - * + * * Side effects: * Everything related to the window is destroyed and the window * is removed from the window lists. Focus is set to the previous on the * window list. - *---------------------------------------------------------------------- + *---------------------------------------------------------------------- */ void wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed) @@ -1740,10 +1843,10 @@ wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed) /* deselect window */ wSelectWindow(wwin, False); - + /* remove all pending events on window */ /* I think this only matters for autoraise */ - if (wPreferences.raise_delay) + if (wPreferences.raise_delay) WMDeleteTimerWithClientData(wwin->frame->core); XFlush(dpy); @@ -1764,7 +1867,7 @@ wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed) } wasFocused = wwin->flags.focused; - + /* remove from window focus list */ if (!wwin->prev && !wwin->next) { /* was the only window */ @@ -1785,7 +1888,7 @@ wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed) if (wPreferences.focus_mode==WKF_CLICK) { /* if in click to focus mode and the window - * was a transient, focus the owner window + * was a transient, focus the owner window */ tmp = NULL; if (wPreferences.focus_mode==WKF_CLICK) { @@ -1864,7 +1967,7 @@ wWindowMap(WWindow *wwin) XMapWindow(dpy, wwin->frame->core->window); if (!wwin->flags.shaded) { /* window will be remapped when getting MapNotify */ - XSelectInput(dpy, wwin->client_win, + XSelectInput(dpy, wwin->client_win, wwin->event_mask & ~StructureNotifyMask); XMapWindow(dpy, wwin->client_win); XSelectInput(dpy, wwin->client_win, wwin->event_mask); @@ -1880,7 +1983,7 @@ wWindowUnmap(WWindow *wwin) wwin->flags.mapped = 0; /* prevent window withdrawal when getting UnmapNotify */ - XSelectInput(dpy, wwin->client_win, + XSelectInput(dpy, wwin->client_win, wwin->event_mask & ~StructureNotifyMask); XUnmapWindow(dpy, wwin->client_win); XSelectInput(dpy, wwin->client_win, wwin->event_mask); @@ -1961,10 +2064,10 @@ wWindowUnfocus(WWindow *wwin) CloseWindowMenu(wwin->screen_ptr); if (wwin->flags.is_gnustep == 0) - wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused + wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused ? WS_PFOCUSED : WS_UNFOCUSED); - if (wwin->transient_for!=None + if (wwin->transient_for!=None && wwin->transient_for!=wwin->screen_ptr->root_win) { WWindow *owner; owner = wWindowFor(wwin->transient_for); @@ -1988,12 +2091,12 @@ void wWindowUpdateName(WWindow *wwin, char *newTitle) { char *title; - + if (!wwin->frame) return; - + wwin->flags.wm_name_changed = 1; - + if (!newTitle) { /* the hint was removed */ title = DEF_WINDOW_TITLE; @@ -2010,16 +2113,16 @@ wWindowUpdateName(WWindow *wwin, char *newTitle) /* *---------------------------------------------------------------------- - * + * * wWindowConstrainSize-- * Constrains size for the client window, taking the maximal size, * window resize increments and other size hints into account. - * + * * Returns: - * The closest size to what was given that the client window can + * The closest size to what was given that the client window can * have. - * - *---------------------------------------------------------------------- + * + *---------------------------------------------------------------------- */ void wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight) @@ -2049,7 +2152,7 @@ wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight) maxAX = wwin->normal_hints->max_aspect.x; maxAY = wwin->normal_hints->max_aspect.y; } - + baseW = wwin->normal_hints->base_width; baseH = wwin->normal_hints->base_height; } @@ -2061,7 +2164,7 @@ wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight) if (width > maxW) width = maxW; - if (height > maxH) + if (height > maxH) height = maxH; /* aspect ratio code borrowed from olwm */ @@ -2122,7 +2225,7 @@ wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight) void -wWindowCropSize(WWindow *wwin, int maxW, int maxH, +wWindowCropSize(WWindow *wwin, int maxW, int maxH, int *width, int *height) { int baseW = 0, baseH = 0; @@ -2131,16 +2234,16 @@ wWindowCropSize(WWindow *wwin, int maxW, int maxH, if (wwin->normal_hints) { baseW = wwin->normal_hints->base_width; baseH = wwin->normal_hints->base_height; - + winc = wwin->normal_hints->width_inc; - hinc = wwin->normal_hints->height_inc; + hinc = wwin->normal_hints->height_inc; } if (*width > maxW) *width = maxW - (maxW - baseW) % winc; if (*height > maxH) - *height = maxH - (maxH - baseH) % hinc; + *height = maxH - (maxH - baseH) % hinc; } @@ -2151,7 +2254,7 @@ wWindowChangeWorkspace(WWindow *wwin, int workspace) WApplication *wapp; int unmap = 0; - if (workspace >= scr->workspace_count || workspace < 0 + if (workspace >= scr->workspace_count || workspace < 0 || workspace == wwin->frame->workspace) return; @@ -2183,14 +2286,14 @@ wWindowChangeWorkspace(WWindow *wwin, int workspace) XMapWindow(dpy, wwin->icon->core->window); wwin->icon->mapped = 1; } - } else if (!wwin->flags.mapped && + } else if (!wwin->flags.mapped && !(wwin->flags.miniaturized || wwin->flags.hidden)) { wWindowMap(wwin); } } if (!IS_OMNIPRESENT(wwin)) { int oldWorkspace = wwin->frame->workspace; - + wwin->frame->workspace = workspace; WMPostNotificationName(WMNChangedWorkspace, wwin, (void*)oldWorkspace); @@ -2218,7 +2321,7 @@ wWindowSynthConfigureNotify(WWindow *wwin) sevent.xconfigure.height = wwin->client.height; sevent.xconfigure.border_width = wwin->old_border_width; - if (WFLAGP(wwin, no_titlebar)) + if (!HAS_TITLEBAR(wwin)) sevent.xconfigure.above = None; else sevent.xconfigure.above = wwin->frame->titlebar->window; @@ -2235,23 +2338,23 @@ wWindowSynthConfigureNotify(WWindow *wwin) /* *---------------------------------------------------------------------- * wWindowConfigure-- - * Configures the frame, decorations and client window to the + * Configures the frame, decorations and client window to the * specified geometry. The geometry is not checked for validity, - * wWindowConstrainSize() must be used for that. + * wWindowConstrainSize() must be used for that. * The size parameters are for the client window, but the position is * for the frame. * The client window receives a ConfigureNotify event, according * to what ICCCM says. - * + * * Returns: * None - * + * * Side effects: * Window size and position are changed and client window receives * a ConfigureNotify event. - *---------------------------------------------------------------------- + *---------------------------------------------------------------------- */ -void +void wWindowConfigure(wwin, req_x, req_y, req_width, req_height) WWindow *wwin; int req_x, req_y; /* new position of the frame */ @@ -2259,29 +2362,29 @@ int req_width, req_height; /* new size of the client */ { int synth_notify = False; int resize; - + resize = (req_width!=wwin->client.width || req_height!=wwin->client.height); - /* + /* * if the window is being moved but not resized then * send a synthetic ConfigureNotify */ if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) { synth_notify = True; } - + if (WFLAGP(wwin, dont_move_off)) - wScreenBringInside(wwin->screen_ptr, &req_x, &req_y, + wScreenBringInside(wwin->screen_ptr, &req_x, &req_y, req_width, req_height); if (resize) { if (req_width < MIN_WINDOW_SIZE) req_width = MIN_WINDOW_SIZE; if (req_height < MIN_WINDOW_SIZE) req_height = MIN_WINDOW_SIZE; - + /* If growing, resize inner part before frame, * if shrinking, resize frame before. - * This will prevent the frame (that can have a different color) + * This will prevent the frame (that can have a different color) * to be exposed, causing flicker */ if (req_height > wwin->frame->core->height || req_width > wwin->frame->core->width) @@ -2294,7 +2397,7 @@ int req_width, req_height; /* new size of the client */ } else { int h; - h = req_height + wwin->frame->top_width + h = req_height + wwin->frame->top_width + wwin->frame->bottom_width; wFrameWindowConfigure(wwin->frame, req_x, req_y, req_width, h); @@ -2316,7 +2419,7 @@ int req_width, req_height; /* new size of the client */ } wwin->frame_x = req_x; wwin->frame_y = req_y; - if (!WFLAGP(wwin, no_border)) { + if (HAS_BORDER(wwin)) { wwin->client.x += FRAME_BORDER_WIDTH; wwin->client.y += FRAME_BORDER_WIDTH; } @@ -2333,7 +2436,7 @@ int req_width, req_height; /* new size of the client */ } -void +void wWindowMove(wwin, req_x, req_y) WWindow *wwin; int req_x, req_y; /* new position of the frame */ @@ -2356,7 +2459,7 @@ int req_x, req_y; /* new position of the frame */ wwin->client.x = req_x; wwin->client.y = req_y + wwin->frame->top_width; - if (!WFLAGP(wwin, no_border)) { + if (HAS_BORDER(wwin)) { wwin->client.x += FRAME_BORDER_WIDTH; wwin->client.y += FRAME_BORDER_WIDTH; } @@ -2380,7 +2483,7 @@ wWindowUpdateButtonImages(WWindow *wwin) Pixmap pixmap, mask; WFrameWindow *fwin = wwin->frame; - if (WFLAGP(wwin, no_titlebar)) + if (!HAS_TITLEBAR(wwin)) return; /* miniaturize button */ @@ -2389,7 +2492,7 @@ wWindowUpdateButtonImages(WWindow *wwin) if (wwin->wm_gnustep_attr && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) { pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap; - + if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) { mask = wwin->wm_gnustep_attr->miniaturize_mask; } else { @@ -2402,7 +2505,7 @@ wWindowUpdateButtonImages(WWindow *wwin) wPixmapDestroy(fwin->lbutton_image); fwin->lbutton_image = NULL; } - + if (!fwin->lbutton_image) { fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask); fwin->lbutton_image->client_owned = 1; @@ -2418,25 +2521,25 @@ wWindowUpdateButtonImages(WWindow *wwin) #ifdef XKB_BUTTON_HINT if (!WFLAGP(wwin, no_language_button)) { - if (fwin->languagebutton_image && - !fwin->languagebutton_image->shared) { - wPixmapDestroy(fwin->languagebutton_image); - } - fwin->languagebutton_image = - scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode]; + if (fwin->languagebutton_image && + !fwin->languagebutton_image->shared) { + wPixmapDestroy(fwin->languagebutton_image); + } + fwin->languagebutton_image = + scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode]; } #endif /* close button */ -/* redefine WFLAGP to MGFLAGP to allow broken close operation */ + /* redefine WFLAGP to MGFLAGP to allow broken close operation */ #define MGFLAGP(wwin, FLAG) (wwin)->client_flags.FLAG if (!WFLAGP(wwin, no_close_button)) { - if (wwin->wm_gnustep_attr + if (wwin->wm_gnustep_attr && wwin->wm_gnustep_attr->flags & GSClosePixmapAttr) { pixmap = wwin->wm_gnustep_attr->close_pixmap; - + if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr) mask = wwin->wm_gnustep_attr->close_mask; else @@ -2447,7 +2550,7 @@ wWindowUpdateButtonImages(WWindow *wwin) wPixmapDestroy(fwin->rbutton_image); fwin->rbutton_image = NULL; } - + if (!fwin->rbutton_image) { fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask); fwin->rbutton_image->client_owned = 1; @@ -2460,17 +2563,17 @@ wWindowUpdateButtonImages(WWindow *wwin) wPixmapDestroy(fwin->rbutton_image); fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL]; - + } else if (MGFLAGP(wwin, broken_close)) { - if (fwin->rbutton_image && !fwin->rbutton_image->shared) + if (fwin->rbutton_image && !fwin->rbutton_image->shared) wPixmapDestroy(fwin->rbutton_image); fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE]; } else { - if (fwin->rbutton_image && !fwin->rbutton_image->shared) + if (fwin->rbutton_image && !fwin->rbutton_image->shared) wPixmapDestroy(fwin->rbutton_image); fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE]; @@ -2487,10 +2590,10 @@ wWindowUpdateButtonImages(WWindow *wwin) *--------------------------------------------------------------------------- * wWindowConfigureBorders-- * Update window border configuration according to attribute flags. - * - *--------------------------------------------------------------------------- + * + *--------------------------------------------------------------------------- */ -void +void wWindowConfigureBorders(WWindow *wwin) { if (wwin->frame) { @@ -2498,14 +2601,16 @@ wWindowConfigureBorders(WWindow *wwin) int newy, oldh; flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON; + #ifdef XKB_BUTTON_HINT - flags |= WFF_LANGUAGE_BUTTON; + flags |= WFF_LANGUAGE_BUTTON; #endif - if (!WFLAGP(wwin, no_titlebar)) + + if (HAS_TITLEBAR(wwin)) flags |= WFF_TITLEBAR; - if (!WFLAGP(wwin, no_resizebar) && !WFLAGP(wwin, no_resizable)) + if (HAS_RESIZEBAR(wwin) && IS_RESIZABLE(wwin)) flags |= WFF_RESIZEBAR; - if (!WFLAGP(wwin, no_border)) + if (HAS_BORDER(wwin)) flags |= WFF_BORDER; if (wwin->flags.shaded) flags |= WFF_IS_SHADED; @@ -2526,9 +2631,10 @@ wWindowConfigureBorders(WWindow *wwin) flags |= WFF_LEFT_BUTTON; #ifdef XKB_BUTTON_HINT - if (!WFLAGP(wwin, no_language_button) - && wwin->frame->flags.hide_language_button) - flags |= WFF_LANGUAGE_BUTTON; + if (!WFLAGP(wwin, no_language_button) + && wwin->frame->flags.hide_language_button) { + flags |= WFF_LANGUAGE_BUTTON; + } #endif if (!WFLAGP(wwin, no_close_button) @@ -2610,7 +2716,7 @@ getSavedState(Window window, WSavedState **state) unsigned long nitems_ret; unsigned long bytes_after_ret; CARD32 *data; - + if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0, 10, True, _XA_WINDOWMAKER_STATE, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, @@ -2634,7 +2740,7 @@ getSavedState(Window window, WSavedState **state) if (*state && type_ret==_XA_WINDOWMAKER_STATE) return 1; - else + else return 0; } @@ -2648,7 +2754,7 @@ wWindowClearShape(WWindow *wwin) XFlush(dpy); } -void +void wWindowSetShape(WWindow *wwin) { XRectangle rect[2]; @@ -2659,10 +2765,10 @@ wWindowSetShape(WWindow *wwin) int ordering; /* only shape is the client's */ - if (WFLAGP(wwin, no_titlebar) && WFLAGP(wwin, no_resizebar)) { + if (!HAS_TITLEBAR(wwin) && !HAS_RESIZEBAR(wwin)) { goto alt_code; } - + /* Get array of rectangles describing the shape mask */ rects = XShapeGetRectangles(dpy, wwin->client_win, ShapeBounding, &count, &ordering); @@ -2680,16 +2786,16 @@ wWindowSetShape(WWindow *wwin) memcpy(urec, rects, sizeof(XRectangle)*count); XFree(rects); - if (!WFLAGP(wwin, no_titlebar)) { + if (HAS_TITLEBAR(wwin)) { urec[count].x = -1; urec[count].y = -1 - wwin->frame->top_width; urec[count].width = wwin->frame->core->width + 2; urec[count].height = wwin->frame->top_width + 1; count++; } - if (!WFLAGP(wwin, no_resizebar)) { + if (HAS_RESIZEBAR(wwin)) { urec[count].x = -1; - urec[count].y = wwin->frame->core->height + urec[count].y = wwin->frame->core->height - wwin->frame->bottom_width - wwin->frame->top_width; urec[count].width = wwin->frame->core->width + 2; urec[count].height = wwin->frame->bottom_width + 1; @@ -2707,14 +2813,14 @@ wWindowSetShape(WWindow *wwin) alt_code: #endif /* OPTIMIZE_SHAPE */ count = 0; - if (!WFLAGP(wwin, no_titlebar)) { + if (HAS_TITLEBAR(wwin)) { rect[count].x = -1; rect[count].y = -1; rect[count].width = wwin->frame->core->width + 2; rect[count].height = wwin->frame->top_width + 1; count++; } - if (!WFLAGP(wwin, no_resizebar)) { + if (HAS_RESIZEBAR(wwin)) { rect[count].x = -1; rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width; rect[count].width = wwin->frame->core->width + 2; @@ -2778,7 +2884,7 @@ wWindowSetKeyGrabs(WWindow *wwin) * work even if the NumLock/ScrollLock key is on. */ wHackedGrabKey(key->keycode, key->modifier, - wwin->frame->core->window, True, GrabModeAsync, + wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync); #endif } @@ -2798,7 +2904,7 @@ wWindowResetMouseGrabs(WWindow *wwin) { /* Mouse grabs can't be done on the client window because of * ICCCM and because clients that try to do the same will crash. - * + * * But there is a problem wich makes tbar buttons of unfocused * windows not usable as the click goes to the frame window instead * of the button itself. Must figure a way to fix that. @@ -2812,7 +2918,7 @@ wWindowResetMouseGrabs(WWindow *wwin) True, ButtonPressMask|ButtonReleaseMask, GrabModeSync, GrabModeAsync, None, None); } - + if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable) && !wwin->flags.is_gnustep) { /* the passive grabs to focus the window */ @@ -2829,7 +2935,7 @@ void wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr) { if (attr->flags & GSExtraFlagsAttr) { - if (MGFLAGP(wwin, broken_close) != + if (MGFLAGP(wwin, broken_close) != (attr->extra_flags & GSDocumentEditedFlag)) { wwin->client_flags.broken_close = !MGFLAGP(wwin, broken_close); wWindowUpdateButtonImages(wwin); @@ -2878,17 +2984,11 @@ wWindowGetSavedState(Window win) { char *instance, *class, *command=NULL; WWindowState *wstate = windowState; - char **argv; - int argc; if (!wstate) return NULL; - if (XGetCommand(dpy, win, &argv, &argc)) { - if (argc > 0) - command = wtokenjoin(argv, argc); - XFreeStringList(argv); - } + command = GetCommandForWindow(win); if (!command) return NULL; @@ -2918,7 +3018,7 @@ wWindowGetSavedState(Window win) } -void +void wWindowDeleteSavedState(WMagicNumber id) { WWindowState *tmp, *wstate=(WWindowState*)id; @@ -2959,7 +3059,7 @@ wWindowDeleteSavedState(WMagicNumber id) } -void +void wWindowDeleteSavedStatesForPID(pid_t pid) { WWindowState *tmp, *wstate; @@ -2998,7 +3098,7 @@ wWindowDeleteSavedStatesForPID(pid_t pid) } tmp = tmp->next; } - } + } } @@ -3015,7 +3115,7 @@ wWindowSetOmnipresent(WWindow *wwin, Bool flag) /* ====================================================================== */ -static void +static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) { WWindow *wwin = data; @@ -3027,12 +3127,12 @@ resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) "Turn it off or some mouse actions and keyboard shortcuts will not work.")); } #endif - + event->xbutton.state &= ValidModMask; - + CloseWindowMenu(wwin->screen_ptr); - if (wPreferences.focus_mode==WKF_CLICK + if (wPreferences.focus_mode==WKF_CLICK && !(event->xbutton.state&ControlMask) && !WFLAGP(wwin, no_focusable)) { wSetFocusTo(wwin->screen_ptr, wwin); @@ -3044,7 +3144,7 @@ resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) if (event->xbutton.window != wwin->frame->resizebar->window) { if (XGrabPointer(dpy, wwin->frame->resizebar->window, True, ButtonMotionMask|ButtonReleaseMask|ButtonPressMask, - GrabModeAsync, GrabModeAsync, None, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime)!=GrabSuccess) { #ifdef DEBUG0 wwarning("pointer grab failed for window move"); @@ -3052,7 +3152,7 @@ resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) return; } } - + if (event->xbutton.state & MOD_MASK) { /* move the window */ wMouseMoveWindow(wwin, event); @@ -3065,7 +3165,7 @@ resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) -static void +static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event) { WWindow *wwin = data; @@ -3086,7 +3186,7 @@ titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event) if (event->xbutton.state & ControlMask) dir |= MAX_VERTICAL; - + if (event->xbutton.state & ShiftMask) { dir |= MAX_HORIZONTAL; if (!(event->xbutton.state & ControlMask)) @@ -3094,7 +3194,7 @@ titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event) } /* maximize window */ - if (dir!=0 && !WFLAGP(wwin, no_resizable)) { + if (dir!=0 && IS_RESIZABLE(wwin)) { int ndir = dir ^ wwin->flags.maximized; if (ndir != 0) { @@ -3124,7 +3224,7 @@ frameMouseDown(WObjDescriptor *desc, XEvent *event) WWindow *wwin = desc->parent; event->xbutton.state &= ValidModMask; - + CloseWindowMenu(wwin->screen_ptr); if (/*wPreferences.focus_mode==WKF_CLICK @@ -3135,10 +3235,10 @@ frameMouseDown(WObjDescriptor *desc, XEvent *event) if (event->xbutton.button == Button1) { wRaiseFrame(wwin->frame->core); } - + if (event->xbutton.state & MOD_MASK) { /* move the window */ - if (XGrabPointer(dpy, wwin->client_win, False, + if (XGrabPointer(dpy, wwin->client_win, False, ButtonMotionMask|ButtonReleaseMask|ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime)!=GrabSuccess) { @@ -3147,7 +3247,7 @@ frameMouseDown(WObjDescriptor *desc, XEvent *event) #endif return; } - if (event->xbutton.button == Button3 && !WFLAGP(wwin, no_resizable)) + if (event->xbutton.button == Button3) wMouseResizeWindow(wwin, event); else if (event->xbutton.button==Button1 || event->xbutton.button==Button2) wMouseMoveWindow(wwin, event); @@ -3156,7 +3256,7 @@ frameMouseDown(WObjDescriptor *desc, XEvent *event) } -static void +static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) { WWindow *wwin = (WWindow*)data; @@ -3172,7 +3272,7 @@ titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) CloseWindowMenu(wwin->screen_ptr); - if (wPreferences.focus_mode==WKF_CLICK + if (wPreferences.focus_mode==WKF_CLICK && !(event->xbutton.state&ControlMask) && !WFLAGP(wwin, no_focusable)) { wSetFocusTo(wwin->screen_ptr, wwin); @@ -3180,7 +3280,7 @@ titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) if (event->xbutton.button == Button1 || event->xbutton.button == Button2) { - + if (event->xbutton.button == Button1) { if (event->xbutton.state & MOD_MASK) { wLowerFrame(wwin->frame->core); @@ -3196,7 +3296,7 @@ titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) if (event->xbutton.window != wwin->frame->titlebar->window && XGrabPointer(dpy, wwin->frame->titlebar->window, False, ButtonMotionMask|ButtonReleaseMask|ButtonPressMask, - GrabModeAsync, GrabModeAsync, None, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime)!=GrabSuccess) { #ifdef DEBUG0 wwarning("pointer grab failed for window move"); @@ -3216,7 +3316,7 @@ titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) if (event->xbutton.window != wwin->frame->titlebar->window && XGrabPointer(dpy, wwin->frame->titlebar->window, False, ButtonMotionMask|ButtonReleaseMask|ButtonPressMask, - GrabModeAsync, GrabModeAsync, None, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime)!=GrabSuccess) { #ifdef DEBUG0 wwarning("pointer grab failed for window move"); @@ -3224,14 +3324,14 @@ titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event) return; } - OpenWindowMenu(wwin, event->xbutton.x_root, + OpenWindowMenu(wwin, event->xbutton.x_root, wwin->frame_y+wwin->frame->top_width, False); /* allow drag select */ desc = &wwin->screen_ptr->window_menu->menu->descriptor; event->xany.send_event = True; (*desc->handle_mousedown)(desc, event); - + XUngrabPointer(dpy, CurrentTime); } } @@ -3309,8 +3409,8 @@ windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event) wwin->frame->languagemode = wwin->frame->last_languagemode; wwin->frame->last_languagemode = tl; wSetFocusTo(scr, wwin); - wwin->frame->languagebutton_image = - wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 + + wwin->frame->languagebutton_image = + wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 + wwin->frame->languagemode]; wFrameWindowUpdateLanguageButton(wwin->frame); if (event->xbutton.button == Button3) @@ -3326,7 +3426,7 @@ windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event) WWindow *wwin = data; event->xbutton.state &= ValidModMask; - + CloseWindowMenu(wwin->screen_ptr); if (event->xbutton.button < Button1 || event->xbutton.button > Button3) @@ -3339,7 +3439,7 @@ windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event) WApplication *wapp; if ((event->xbutton.state & ControlMask) || (event->xbutton.button == Button3)) { - + wapp = wApplicationOf(wwin->main_window); if (wapp && !WFLAGP(wwin, no_appicon)) wHideApplication(wapp); diff --git a/src/window.h b/src/window.h index 74005745..a8b359db 100644 --- a/src/window.h +++ b/src/window.h @@ -95,6 +95,7 @@ typedef struct { #ifdef XKB_BUTTON_HINT unsigned int no_language_button:1; #endif + unsigned int no_movable:1; /* decorations */ unsigned int no_resizebar:1; /* draw the bottom handle? */ @@ -135,6 +136,10 @@ typedef struct { unsigned int full_maximize:1; +#ifdef VIRTUAL_DESKTOP + unsigned int virtual_stick:1; +#endif + /* * emulate_app_icon must be automatically disabled for apps that can * generate their own appicons and for apps that have no_appicon=1 @@ -201,6 +206,11 @@ typedef struct WWindow { unsigned int width, height; /* original geometry of the window */ } old_geometry; /* (before things like maximize) */ + struct { + int x, y; + unsigned int width, height; /* original geometry of the window */ + } bfs_geometry; /* (before fullscreen) */ + /* client window info */ short old_border_width; /* original border width of client_win*/ Window client_win; /* the window we're managing */ @@ -257,6 +267,7 @@ typedef struct WWindow { unsigned int hidden:1; unsigned int shaded:1; unsigned int maximized:2; + unsigned int fullscreen:1; unsigned int omnipresent:1; unsigned int semi_focused:1; @@ -307,19 +318,36 @@ typedef struct WWindow { unsigned int olwm_push_pin_out:1;/* emulate pushpin behaviour */ unsigned int olwm_limit_menu:1; #endif -#ifdef NET_HINTS +#ifdef NETWM_HINTS unsigned int net_state_from_client:1; /* state hint was set by client */ - unsigned int net_skip_taskbar:1; unsigned int net_skip_pager:1; + unsigned int net_handle_icon:1; + unsigned int net_show_desktop:1; #endif } flags; /* state of the window */ struct WIcon *icon; /* icon info for the window */ int icon_x, icon_y; /* position of the icon */ +#ifdef NETWM_HINTS + int icon_w, icon_h; + RImage *net_icon_image; + Atom type; +#endif } WWindow; -#define IS_OMNIPRESENT(w) ((w)->flags.omnipresent ^ WFLAGP(w, omnipresent)) +#define HAS_TITLEBAR(w) (!(WFLAGP((w), no_titlebar) || (w)->flags.fullscreen)) +#define HAS_RESIZEBAR(w) (!(WFLAGP((w), no_resizebar) || (w)->flags.fullscreen)) +#define HAS_BORDER(w) (!(WFLAGP((w), no_border) || (w)->flags.fullscreen)) +#define IS_MOVABLE(w) (!(WFLAGP((w), no_movable) || (w)->flags.fullscreen)) +#define IS_RESIZABLE(w) (!(WFLAGP((w), no_resizable) || (w)->flags.fullscreen)) + +#ifdef VIRTUAL_DESKTOP +# define IS_VSTUCK(w) (WFLAGP((w), virtual_stick) || (w)->flags.fullscreen) +#endif + +/* XXX: CHECK THIS,.. IT SEEMED WEIRD TO ME!!! */ +#define IS_OMNIPRESENT(w) ((w)->flags.omnipresent | WFLAGP(w, omnipresent)) #define WINDOW_LEVEL(w) ((w)->frame->core->stacking->window_level) diff --git a/src/winmenu.c b/src/winmenu.c index 84462d2e..fe8f7215 100644 --- a/src/winmenu.c +++ b/src/winmenu.c @@ -586,10 +586,10 @@ updateMenuForWindow(WMenu *menu, WWindow *wwin) menu->entries[MC_MAXIMIZE]->text = text; } - wMenuSetEnabled(menu, MC_MAXIMIZE, !WFLAGP(wwin, no_resizable)); + wMenuSetEnabled(menu, MC_MAXIMIZE, IS_RESIZABLE(wwin)); - wMenuSetEnabled(menu, MC_MOVERESIZE, !WFLAGP(wwin, no_resizable) + wMenuSetEnabled(menu, MC_MOVERESIZE, IS_RESIZABLE(wwin) && !wwin->flags.miniaturized); if (wwin->flags.shaded) { diff --git a/src/winspector.c b/src/winspector.c index 9cec2677..9e52df36 100644 --- a/src/winspector.c +++ b/src/winspector.c @@ -47,6 +47,11 @@ #include "dock.h" #include "client.h" +#ifdef NETWM_HINTS +#include "wmspec.h" +#endif + +#include "xinerama.h" #include @@ -540,7 +545,7 @@ saveSettings(WMButton *button, InspectorPanel *panel) return; if (!dict) { - dict = WMCreatePLDictionary(NULL, NULL, NULL); + dict = WMCreatePLDictionary(NULL, NULL); if (dict) { db->dictionary = dict; } else { @@ -555,8 +560,8 @@ saveSettings(WMButton *button, InspectorPanel *panel) WMPLSetCaseSensitive(True); - winDic = WMCreatePLDictionary(NULL, NULL, NULL); - appDic = WMCreatePLDictionary(NULL, NULL, NULL); + winDic = WMCreatePLDictionary(NULL, NULL); + appDic = WMCreatePLDictionary(NULL, NULL); /* Update icon for window */ icon_file = WMGetTextFieldText(panel->fileText); @@ -875,6 +880,9 @@ applySettings(WMButton *button, InspectorPanel *panel) wwin->frame->flags.need_texture_change = 1; wWindowConfigureBorders(wwin); wFrameWindowPaint(wwin->frame); +#ifdef NETWM_HINTS + wNETWMUpdateActions(wwin, False); +#endif /* * Can't apply emulate_appicon because it will probably cause problems. diff --git a/src/wmspec.c b/src/wmspec.c index 87df9e50..a96231ae 100644 --- a/src/wmspec.c +++ b/src/wmspec.c @@ -1,9 +1,9 @@ /* wmspec.c-- support for the wm-spec Hints - * + * * Window Maker window manager - * + * * Copyright (c) 1998-2003 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 @@ -16,23 +16,42 @@ * * 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, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "wconfig.h" +#ifdef NETWM_HINTS + #include #include +#include #include "WindowMaker.h" #include "window.h" #include "screen.h" +#include "workspace.h" #include "framewin.h" #include "actions.h" +#include "client.h" +#include "wmspec.h" +#include "icon.h" +#include "stacking.h" +#include "xinerama.h" +#ifdef DEBUG_WMSPEC +#include +#endif + +/* Global variables */ +extern Atom _XA_WM_DELETE_WINDOW; +extern Time LastTimestamp; +extern WPreferences wPreferences; + +/* Root Window Properties */ static Atom net_supported; static Atom net_client_list; static Atom net_client_list_stacking; @@ -40,156 +59,439 @@ static Atom net_number_of_desktops; static Atom net_desktop_geometry; static Atom net_desktop_viewport; static Atom net_current_desktop; +static Atom net_desktop_names; static Atom net_active_window; -static Atom net_workarea; +static Atom net_workarea; /* XXX: not xinerama compatible */ static Atom net_supporting_wm_check; -/* net_virtual_roots N/A */ -/* TODO - * _NET_WM_NAME - * _NET_WM_VISIBLE_NAME - * _NET_WM_ICON_NAME - * _NET_WM_VISIBLE_ICON_NAME - * _NET_WM_WINDOW_TYPE - */ +static Atom net_virtual_roots; /* N/A */ +static Atom net_desktop_layout; /* XXX */ +static Atom net_showing_desktop; + +/* Other Root Window Messages */ +static Atom net_close_window; +static Atom net_moveresize_window; /* TODO */ +static Atom net_wm_moveresize; /* TODO */ + +/* Application Window Properties */ +static Atom net_wm_name; /* TODO */ +static Atom net_wm_visible_name; /* TODO */ +static Atom net_wm_icon_name; /* TODO */ +static Atom net_wm_visible_icon_name; /* TODO */ static Atom net_wm_desktop; +static Atom net_wm_window_type; +static Atom net_wm_window_type_desktop; +static Atom net_wm_window_type_dock; +static Atom net_wm_window_type_toolbar; +static Atom net_wm_window_type_menu; +static Atom net_wm_window_type_utility; +static Atom net_wm_window_type_splash; +static Atom net_wm_window_type_dialog; +static Atom net_wm_window_type_normal; static Atom net_wm_state; - -static Atom net_wm_strut; -/* - * _NET_WM_ICON_GEOMETRY - * _NET_WM_ICON - * _NET_WM_PID - * _NET_WM_HANDLED_ICONS - * - */ - -static Atom net_wm_state_modal; +static Atom net_wm_state_modal; /* XXX: what is this?!? */ static Atom net_wm_state_sticky; static Atom net_wm_state_maximized_vert; static Atom net_wm_state_maximized_horz; static Atom net_wm_state_shaded; static Atom net_wm_state_skip_taskbar; static Atom net_wm_state_skip_pager; +static Atom net_wm_state_hidden; +static Atom net_wm_state_fullscreen; +static Atom net_wm_state_above; +static Atom net_wm_state_below; +static Atom net_wm_allowed_actions; +static Atom net_wm_action_move; +static Atom net_wm_action_resize; +static Atom net_wm_action_minimize; +static Atom net_wm_action_shade; +static Atom net_wm_action_stick; +static Atom net_wm_action_maximize_horz; +static Atom net_wm_action_maximize_vert; +static Atom net_wm_action_fullscreen; +static Atom net_wm_action_change_desktop; +static Atom net_wm_action_close; +static Atom net_wm_strut; /* XXX: see net_workarea */ +static Atom net_wm_strut_partial; /* TODO: doesn't really fit into the current strut scheme */ +static Atom net_wm_icon_geometry; /* FIXME: should work together with net_wm_handled_icons, gnome-panel-2.2.0.1 doesn't use _NET_WM_HANDLED_ICONS, thus present situation. */ +static Atom net_wm_icon; +static Atom net_wm_pid; /* TODO */ +static Atom net_wm_handled_icons; /* FIXME: see net_wm_icon_geometry */ + +/* Window Manager Protocols */ +static Atom net_wm_ping; /* TODO */ + +static Atom utf8_string; + +typedef struct { + char * name; + Atom * atom; +} atomitem_t; + +static atomitem_t atomNames[] = { + { "_NET_SUPPORTED", &net_supported }, + { "_NET_CLIENT_LIST", &net_client_list }, + { "_NET_CLIENT_LIST_STACKING", &net_client_list_stacking }, + { "_NET_NUMBER_OF_DESKTOPS", &net_number_of_desktops }, + { "_NET_DESKTOP_GEOMETRY", &net_desktop_geometry }, + { "_NET_DESKTOP_VIEWPORT", &net_desktop_viewport }, + { "_NET_CURRENT_DESKTOP", &net_current_desktop }, + { "_NET_DESKTOP_NAMES", &net_desktop_names }, + { "_NET_ACTIVE_WINDOW", &net_active_window }, + { "_NET_WORKAREA", &net_workarea }, + { "_NET_SUPPORTING_WM_CHECK", &net_supporting_wm_check }, + { "_NET_VIRTUAL_ROOTS", &net_virtual_roots }, + { "_NET_DESKTOP_LAYOUT", &net_desktop_layout }, + { "_NET_SHOWING_DESKTOP", &net_showing_desktop }, + + { "_NET_CLOSE_WINDOW", &net_close_window }, + { "_NET_MOVERESIZE_WINDOW", &net_moveresize_window }, + { "_NET_WM_MOVERESIZE", &net_wm_moveresize }, + + { "_NET_WM_NAME", &net_wm_name }, + { "_NET_WM_VISIBLE_NAME", &net_wm_visible_name }, + { "_NET_WM_ICON_NAME", &net_wm_icon_name }, + { "_NET_WM_VISIBLE_ICON_NAME", &net_wm_visible_icon_name }, + { "_NET_WM_DESKTOP", &net_wm_desktop }, + { "_NET_WM_WINDOW_TYPE", &net_wm_window_type }, + { "_NET_WM_WINDOW_TYPE_DESKTOP", &net_wm_window_type_desktop }, + { "_NET_WM_WINDOW_TYPE_DOCK", &net_wm_window_type_dock }, + { "_NET_WM_WINDOW_TYPE_TOOLBAR", &net_wm_window_type_toolbar }, + { "_NET_WM_WINDOW_TYPE_MENU", &net_wm_window_type_menu }, + { "_NET_WM_WINDOW_TYPE_UTILITY", &net_wm_window_type_utility }, + { "_NET_WM_WINDOW_TYPE_SPLASH", &net_wm_window_type_splash }, + { "_NET_WM_WINDOW_TYPE_DIALOG", &net_wm_window_type_dialog }, + { "_NET_WM_WINDOW_TYPE_NORMAL", &net_wm_window_type_normal }, + { "_NET_WM_STATE", &net_wm_state }, + { "_NET_WM_STATE_MODAL", &net_wm_state_modal }, + { "_NET_WM_STATE_STICKY", &net_wm_state_sticky }, + { "_NET_WM_STATE_MAXIMIZED_VERT", &net_wm_state_maximized_vert }, + { "_NET_WM_STATE_MAXIMIZED_HORZ", &net_wm_state_maximized_horz }, + { "_NET_WM_STATE_SHADED", &net_wm_state_shaded }, + { "_NET_WM_STATE_SKIP_TASKBAR", &net_wm_state_skip_taskbar }, + { "_NET_WM_STATE_SKIP_PAGER", &net_wm_state_skip_pager }, + { "_NET_WM_STATE_HIDDEN", &net_wm_state_hidden }, + { "_NET_WM_STATE_FULLSCREEN", &net_wm_state_fullscreen }, + { "_NET_WM_STATE_ABOVE", &net_wm_state_above }, + { "_NET_WM_STATE_BELOW", &net_wm_state_below }, + { "_NET_WM_ALLOWED_ACTIONS", &net_wm_allowed_actions }, + { "_NET_WM_ACTION_MOVE", &net_wm_action_move }, + { "_NET_WM_ACTION_RESIZE", &net_wm_action_resize }, + { "_NET_WM_ACTION_MINIMIZE", &net_wm_action_minimize }, + { "_NET_WM_ACTION_SHADE", &net_wm_action_shade }, + { "_NET_WM_ACTION_STICK", &net_wm_action_stick }, + { "_NET_WM_ACTION_MAXIMIZE_HORZ", &net_wm_action_maximize_horz }, + { "_NET_WM_ACTION_MAXIMIZE_VERT", &net_wm_action_maximize_vert }, + { "_NET_WM_ACTION_FULLSCREEN", &net_wm_action_fullscreen }, + { "_NET_WM_ACTION_CHANGE_DESKTOP", &net_wm_action_change_desktop }, + { "_NET_WM_ACTION_CLOSE", &net_wm_action_close }, + { "_NET_WM_STRUT", &net_wm_strut }, + { "_NET_WM_STRUT_PARTIAL", &net_wm_strut_partial }, + { "_NET_WM_ICON_GEOMETRY", &net_wm_icon_geometry }, + { "_NET_WM_ICON", &net_wm_icon }, + { "_NET_WM_PID", &net_wm_pid }, + { "_NET_WM_HANDLED_ICONS", &net_wm_handled_icons }, + + { "_NET_WM_PING", &net_wm_ping }, + + { "UTF8_STRING", &utf8_string }, +}; +#define atomNr (sizeof(atomNames)/sizeof(atomitem_t)) +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 -/* states */ - - -static char *atomNames[] = { - "_NET_SUPPORTED", - "_NET_CLIENT_LIST", - "_NET_NUMBER_OF_DESKTOPS", - "_NET_DESKTOP_GEOMETRY", - "_NET_DESKTOP_VIEWPORT", - "_NET_CURRENT_DESKTOP", - "_NET_ACTIVE_WINDOW", - "_NET_WORKAREA", - "_NET_SUPPORTING_WM_CHECK", - "_NET_WM_DESKTOP", - "_NET_WM_STATE", - "_NET_WM_STRUT", - - - - "_NET_WM_STATE_MODAL", - "_NET_WM_STATE_STICKY", - "_NET_WM_STATE_MAXIMIZED_VERT", - "_NET_WM_STATE_MAXIMIZED_HORZ", - "_NET_WM_STATE_SHADED", - "_NET_WM_STATE_SKIP_TASKBAR", - "_NET_WM_STATE_SKIP_PAGER" -}; +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */ +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ static void observer(void *self, WMNotification *notif); static void wsobserver(void *self, WMNotification *notif); +static void updateClientList(WScreen *scr); +static void updateClientListStacking(WScreen *scr, WWindow *); + +static void updateWorkspaceNames(WScreen *scr); +static void updateCurrentWorkspace(WScreen *scr); +static void updateWorkspaceCount(WScreen *scr); typedef struct NetData { WScreen *scr; - Window *client_windows; - int client_count; - int client_size; + WReservedArea *strut; + WWindow **show_desktop; } NetData; - - - -static void setSupportedHints(WScreen *scr) +static void +setSupportedHints(WScreen *scr) { - Atom atom[32]; + Atom atom[atomNr]; int i = 0; - unsigned int sizes[2]; - + /* set supported hints list */ - + /* XXX: extend this !!! */ + atom[i++] = net_client_list; + atom[i++] = net_client_list_stacking; + atom[i++] = net_number_of_desktops; + atom[i++] = net_desktop_geometry; + atom[i++] = net_desktop_viewport; + atom[i++] = net_current_desktop; + atom[i++] = net_desktop_names; + atom[i++] = net_active_window; + atom[i++] = net_workarea; + atom[i++] = net_supporting_wm_check; + atom[i++] = net_showing_desktop; +#if 0 + atom[i++] = net_wm_moveresize; +#endif + atom[i++] = net_wm_desktop; + atom[i++] = net_wm_window_type; + atom[i++] = net_wm_window_type_desktop; + atom[i++] = net_wm_window_type_dock; + atom[i++] = net_wm_window_type_toolbar; + atom[i++] = net_wm_window_type_menu; + atom[i++] = net_wm_window_type_utility; + atom[i++] = net_wm_window_type_splash; + atom[i++] = net_wm_window_type_dialog; + atom[i++] = net_wm_window_type_normal; + + atom[i++] = net_wm_state; + /* atom[i++] = net_wm_state_modal; */ /* XXX: not sure where/when to use it. */ + atom[i++] = net_wm_state_sticky; + atom[i++] = net_wm_state_shaded; + atom[i++] = net_wm_state_maximized_horz; + atom[i++] = net_wm_state_maximized_vert; + atom[i++] = net_wm_state_skip_taskbar; + atom[i++] = net_wm_state_skip_pager; + atom[i++] = net_wm_state_hidden; + atom[i++] = net_wm_state_fullscreen; + atom[i++] = net_wm_state_above; + atom[i++] = net_wm_state_below; + + atom[i++] = net_wm_allowed_actions; + atom[i++] = net_wm_action_move; + atom[i++] = net_wm_action_resize; + atom[i++] = net_wm_action_minimize; + atom[i++] = net_wm_action_shade; + atom[i++] = net_wm_action_stick; + atom[i++] = net_wm_action_maximize_horz; + atom[i++] = net_wm_action_maximize_vert; + atom[i++] = net_wm_action_fullscreen; + atom[i++] = net_wm_action_change_desktop; + atom[i++] = net_wm_action_close; + + atom[i++] = net_wm_strut; + atom[i++] = net_wm_icon_geometry; + atom[i++] = net_wm_icon; + atom[i++] = net_wm_handled_icons; + + XChangeProperty(dpy, scr->root_win, net_supported, XA_ATOM, 32, + PropModeReplace, (unsigned char*)atom, i); - - XChangeProperty(dpy, scr->root_win, - net_supported, XA_ATOM, 32, - PropModeReplace, (unsigned char*)atom, i); - /* set supporting wm hint */ - XChangeProperty(dpy, scr->root_win, - net_supporting_wm_check, XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&scr->info_window, 1); - - XChangeProperty(dpy, scr->info_window, - net_supporting_wm_check, XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&scr->info_window, 1); - - - /* set desktop geometry. dynamic change is not supported */ + XChangeProperty(dpy, scr->root_win, net_supporting_wm_check, XA_WINDOW, 32, + PropModeReplace, (unsigned char*)&scr->info_window, 1); + + XChangeProperty(dpy, scr->info_window, net_supporting_wm_check, XA_WINDOW, + 32, PropModeReplace, (unsigned char*)&scr->info_window, 1); +} + + +void +wNETWMUpdateDesktop(WScreen *scr) +{ + CARD32 *views, sizes[2]; + int count, i; + + if (scr->workspace_count==0) + return; + + count = scr->workspace_count * 2; + views = wmalloc(sizeof(CARD32) * count); + /*memset(views, 0, sizeof(CARD32) * count);*/ + +#ifdef VIRTUAL_DESKTOP + sizes[0] = scr->workspaces[scr->current_workspace]->width; + sizes[1] = scr->workspaces[scr->current_workspace]->height; +#else sizes[0] = scr->scr_width; sizes[1] = scr->scr_height; +#endif + + for (i=0; iworkspace_count; i++) { +#ifdef VIRTUAL_DESKTOP + views[2*i + 0] = scr->workspaces[i]->view_x; + views[2*i + 1] = scr->workspaces[i]->view_y; +#else + views[2*i + 0] = 0; + views[2*i + 1] = 0; +#endif + } + + XChangeProperty(dpy, scr->root_win, net_desktop_geometry, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)sizes, 2); + + XChangeProperty(dpy, scr->root_win, net_desktop_viewport, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)views, count); + + wfree(views); +} + + +static void +updateIconImage(WScreen *scr, WWindow *wwin) +{ + Atom actual_type_return; + int actual_format_return; + unsigned long nitems_return, bytes_after_return; + unsigned char *prop_return; + int rc = XGetWindowProperty(dpy, wwin->client_win, net_wm_icon, 0, ~0, False, + XA_CARDINAL, &actual_type_return, &actual_format_return, + &nitems_return, &bytes_after_return, &prop_return); + + if (rc==Success && prop_return) { + unsigned int *data = (unsigned int *)prop_return; + unsigned int pos = 0, len = 0; + unsigned int best_pos = 0, best_tmp = ~0; + extern WPreferences wPreferences; + unsigned int pref_size = wPreferences.icon_size; + unsigned int pref_sq = pref_size*pref_size; + char *src, *dst; + RImage *new_rimage; + + do { + len = data[pos+0]*data[pos+1]; + unsigned int tmp = pref_sq-len; + if (tmp < best_tmp && tmp > 0) { + best_tmp = tmp; + best_pos = pos; + } + pos += 2+len; + } while (pos < nitems_return && len != 0); + + new_rimage = RCreateImage(data[best_pos+0], data[best_pos+1], True); + len = data[best_pos+0] * data[best_pos+1]; + src = (char*)&data[best_pos+2]; + dst = new_rimage->data; + for (pos=0; posnet_icon_image) + RReleaseImage(wwin->net_icon_image); + wwin->net_icon_image = new_rimage; + } + + XFree(prop_return); + } +} - XChangeProperty(dpy, scr->root_win, - net_desktop_geometry, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)&sizes, 2); - - /* set desktop viewport. dynamic change is not supported */ - sizes[0] = 0; - sizes[1] = 0; - XChangeProperty(dpy, scr->root_win, - net_desktop_viewport, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)&sizes, 2); +static void +updateShowDesktop(WScreen * scr, Bool show) +{ + CARD32 foo; + foo = (show == True); + XChangeProperty(dpy, scr->root_win, net_showing_desktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&foo, 1); } -void netwmInitialize(WScreen *scr) +void +wNETWMShowingDesktop(WScreen *scr, Bool show) +{ + if (show && scr->netdata->show_desktop == NULL) { + WWindow *tmp, **wins; + int i=0; + + wins = (WWindow **)wmalloc(sizeof(WWindow *)*(scr->window_count+1)); + + tmp = scr->focused_window; + while (tmp) { + if (!tmp->flags.hidden && !tmp->flags.miniaturized && + !WFLAGP(tmp, skip_window_list)) { + + wins[i++] = tmp; + tmp->flags.skip_next_animation = 1; + tmp->flags.net_show_desktop = 1; + wIconifyWindow(tmp); + } + + tmp = tmp->prev; + } + wins[i++] = NULL; + + scr->netdata->show_desktop = wins; + updateShowDesktop(scr, True); + } else if (scr->netdata->show_desktop != NULL) { + /* FIXME: get rid of workspace flashing ! */ + int ws = scr->current_workspace; + WWindow **tmp; + for (tmp = scr->netdata->show_desktop; *tmp; ++tmp) { + wDeiconifyWindow(*tmp); + (*tmp)->flags.net_show_desktop = 0; + } + if (ws != scr->current_workspace) + wWorkspaceChange(scr, ws); + wfree(scr->netdata->show_desktop); + scr->netdata->show_desktop = NULL; + updateShowDesktop(scr, False); + } +} + + +void +wNETWMInitStuff(WScreen *scr) { NetData *data; - Atom atom[32]; + int i; + +#ifdef DEBUG_WMSPEC + printf( "wNETWMInitStuff\n"); +#endif #ifdef HAVE_XINTERNATOMS - XInternAtoms(dpy, atomNames, sizeof(atomNames)/sizeof(char*), - False, atom); -#else { - int i; - for (i = 0; i < sizeof(atomNames)/sizeof(char*); i++) { - atom[i] = XInternAtom(dpy, atomNames[i], False); - } + Atom atoms[atomNr]; + char * names[atomNr]; + + for (i = 0; i < atomNr; ++i) { + names[i] = atomNames[i].name; + } + XInternAtoms(dpy, &names[0], atomNr, False, atoms); + for (i = 0; i < atomNr; ++i) { + *atomNames[i].atom = atoms[i]; + } + } +#else + for (i = 0; i < atomNr; i++) { + *atomNames[i].atom = XInternAtom(dpy, atomNames[i].name, False); } #endif - net_supported = atom[0]; - net_client_list = atom[1]; - - setSupportedHints(scr); - + data = wmalloc(sizeof(NetData)); data->scr = scr; - data->client_windows = NULL; - data->client_count = 0; - data->client_size = 0; + data->strut = NULL; + data->show_desktop = NULL; + + scr->netdata = data; + + setSupportedHints(scr); WMAddNotificationObserver(observer, data, WMNManaged, NULL); WMAddNotificationObserver(observer, data, WMNUnmanaged, NULL); @@ -203,233 +505,1057 @@ void netwmInitialize(WScreen *scr) WMAddNotificationObserver(wsobserver, data, WMNWorkspaceDestroyed, NULL); WMAddNotificationObserver(wsobserver, data, WMNWorkspaceChanged, NULL); WMAddNotificationObserver(wsobserver, data, WMNWorkspaceNameChanged, NULL); + + updateClientList(scr); + updateClientListStacking(scr, NULL); + updateWorkspaceCount(scr); + updateCurrentWorkspace(scr); + updateWorkspaceNames(scr); + updateShowDesktop(scr, False); + + wScreenUpdateUsableArea(scr); } void -netwmUpdateWorkarea(WScreen *scr) +wNETWMUpdateActions(WWindow *wwin, Bool del) { - unsigned int area[4]; - - /* XXX */ + Atom action[10]; /* nr of actions atoms defined */ + int i = 0; + + if (del) { + XDeleteProperty(dpy, wwin->client_win, net_wm_allowed_actions); + return; + } + + if (IS_MOVABLE(wwin)) + action[i++] = net_wm_action_move; + + if (IS_RESIZABLE(wwin)) + action[i++] = net_wm_action_resize; + + if (!WFLAGP(wwin, no_miniaturizable)) + action[i++] = net_wm_action_minimize; + + if (!WFLAGP(wwin, no_shadeable)) + action[i++] = net_wm_action_shade; + + /* if (!WFLAGP(wwin, no_stickable)) */ + action[i++] = net_wm_action_stick; + + /* if (!(WFLAGP(wwin, no_maximizeable) & MAX_HORIZONTAL)) */ + if (IS_RESIZABLE(wwin)) + action[i++] = net_wm_action_maximize_horz; + + /* if (!(WFLAGP(wwin, no_maximizeable) & MAX_VERTICAL)) */ + if (IS_RESIZABLE(wwin)) + action[i++] = net_wm_action_maximize_vert; + + /* if (!WFLAGP(wwin, no_fullscreen)) */ + action[i++] = net_wm_action_fullscreen; + + /* if (!WFLAGP(wwin, no_change_desktop)) */ + action[i++] = net_wm_action_change_desktop; + + if (!WFLAGP(wwin, no_closable)) + action[i++] = net_wm_action_close; + + XChangeProperty(dpy, wwin->client_win, net_wm_allowed_actions, + XA_ATOM, 32, PropModeReplace, (unsigned char *)action, i); +} + + +void +wNETWMUpdateWorkarea(WScreen *scr, WArea usableArea) +{ + CARD32 *area; + int count, i; + + /* XXX: not Xinerama compatible, + xinerama gets the largest available */ + + if(!scr->netdata || scr->workspace_count==0) + return; + + count = scr->workspace_count * 4; + area = wmalloc(sizeof(CARD32) * count); + for (i=0; iworkspace_count; i++) { + area[4*i + 0] = usableArea.x1; + area[4*i + 1] = usableArea.y1; + area[4*i + 2] = usableArea.x2 - usableArea.x1; + area[4*i + 3] = usableArea.y2 - usableArea.y1; + } XChangeProperty(dpy, scr->root_win, net_workarea, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)area, 4); + PropModeReplace, (unsigned char*)area, count); + + wfree(area); } +Bool +wNETWMGetUsableArea(WScreen *scr, int head, WArea *area) +{ + WReservedArea *cur; + WMRect rect; + + if(!scr->netdata || !scr->netdata->strut) + return False; + + area->x1 = area->y1 = area->x2 = area->y2 = 0; + + for(cur = scr->netdata->strut ; cur ; cur = cur->next) { + WWindow * wwin = wWindowFor(cur->window); + if (wWindowTouchesHead(wwin, head)) { + if(cur->area.x1 > area->x1) + area->x1 = cur->area.x1; + if(cur->area.y1 > area->y1) + area->y1 = cur->area.y1; + if(cur->area.x2 > area->x2) + area->x2 = cur->area.x2; + if(cur->area.y2 > area->y2) + area->y2 = cur->area.y2; + } + } + + if (area->x1==0 && area->x2==0 && + area->y1==0 && area->y2==0) return False; + + rect = wGetRectForHead(scr, head); + + area->x1 = rect.pos.x + area->x1; + area->x2 = rect.pos.x + rect.size.width - area->x2; + area->y1 = rect.pos.y + area->y1; + area->y2 = rect.pos.y + rect.size.height - area->y2; + + return True; +} + static void -updateClientList(WScreen *scr, WWindow *wwin, Bool added) +updateClientList(WScreen *scr) { - NetData *data = scr->netdata; - - if (added) { - if (data->client_count == data->client_size) { - data->client_size += 20; - data->client_windows = wrealloc(data->client_windows, - sizeof(Window)*data->client_size); - } + WWindow *wwin; + Window *windows; + int count; - data->client_windows[data->client_count++] = wwin->client_win; + windows = (Window *)wmalloc(sizeof(Window)*(scr->window_count+1)); - XChangeProperty(dpy, scr->root_win, net_client_list, XA_WINDOW, 32, - PropModeAppend, (unsigned char*)&wwin->client_win, 1); - } else { - int i; - for (i = 0; i < data->client_count; i++) { - if (data->client_windows[i] == wwin->client_win) { - if (data->client_count-1 > i) { - memmove(data->client_windows+i, - data->client_windows+i+1, - (data->client_count-i-1)*sizeof(Window)); - } - data->client_count--; - break; - } - } - - /* update client list */ - XChangeProperty(dpy, scr->root_win, net_client_list, XA_WINDOW, 32, - PropModeReplace, - (unsigned char *)data->client_windows, - data->client_count); + count = 0; + wwin = scr->focused_window; + while (wwin) { + windows[count++] = wwin->client_win; + wwin = wwin->prev; } + XChangeProperty(dpy, scr->root_win, net_client_list, XA_WINDOW, 32, + PropModeReplace, (unsigned char*)windows, count); + + wfree(windows); XFlush(dpy); } - static void -updateClientListStacking(WScreen *scr) +updateClientListStacking(WScreen *scr, WWindow *wwin_excl) { WWindow *wwin; Window *client_list; + Window *client_list_reverse; int client_count; WCoreWindow *tmp; WMBagIterator iter; + int i; /* update client list */ - - client_list = (Window*)malloc(sizeof(Window)*scr->window_count); - if (!client_list) { - wwarning(_("out of memory while updating wm hints")); - return; - } + i = scr->window_count + 1; + client_list = (Window*)wmalloc(sizeof(Window) * i); + client_list_reverse = (Window*)wmalloc(sizeof(Window) * i); + client_count = 0; WM_ETARETI_BAG(scr->stacking_list, tmp, iter) { - while (tmp) { - client_list[client_count++] = tmp->window; - tmp = tmp->stacking->under; - } + while (tmp) { + wwin = wWindowFor(tmp->window); + /* wwin_excl is a window to exclude from the list + (e.g. it's now unmanaged) */ + if(wwin && (wwin != wwin_excl)) + client_list[client_count++] = wwin->client_win; + tmp = tmp->stacking->under; + } } - XChangeProperty(dpy, scr->root_win, - net_client_list_stacking, XA_WINDOW, 32, - PropModeReplace, - (unsigned char *)client_list, client_count); + for(i = 0; i < client_count; i++) { + Window w = client_list[client_count - i - 1]; + client_list_reverse[i] = w; + } + + XChangeProperty(dpy, scr->root_win, net_client_list_stacking, XA_WINDOW, 32, + PropModeReplace, (unsigned char *)client_list_reverse, client_count); wfree(client_list); + wfree(client_list_reverse); XFlush(dpy); } - static void updateWorkspaceCount(WScreen *scr) /* changeable */ { - unsigned int count = scr->workspace_count; - - XChangeProperty(dpy, scr->root_win, - net_number_of_desktops, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)&count, 1); + CARD32 count; + + count = scr->workspace_count; + + XChangeProperty(dpy, scr->root_win, net_number_of_desktops, XA_CARDINAL, + 32, PropModeReplace, (unsigned char*)&count, 1); } static void updateCurrentWorkspace(WScreen *scr) /* changeable */ { - unsigned int count = scr->current_workspace; - - XChangeProperty(dpy, scr->root_win, - net_current_desktop, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)&count, 1); + CARD32 count; + + count = scr->current_workspace; + + XChangeProperty(dpy, scr->root_win, net_current_desktop, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*)&count, 1); } static void -updateWorkspaceNames(WScreen *scr, int workspace) +updateWorkspaceNames(WScreen *scr) { - /* XXX UTF 8 */ + char buf[1024], *pos; + unsigned int i, len, curr_size; + + pos = buf; + len = 0; + for(i = 0; i < scr->workspace_count; i++) { + curr_size = strlen(scr->workspaces[i]->name); + strcpy(pos, scr->workspaces[i]->name); + pos += (curr_size+1); + len += (curr_size+1); + } + + XChangeProperty(dpy, scr->root_win, net_desktop_names, utf8_string, 8, + PropModeReplace, (unsigned char *)buf, len); } static void updateFocusHint(WScreen *scr, WWindow *wwin) /* changeable */ { - Window window = None; - - if (wwin) - window = wwin->client_win; - - XChangeProperty(dpy, scr->root_win, - net_active_window, XA_WINDOW, 32, - PropModeReplace, - (unsigned char*)&window, 1); + Window window; + + if (!scr->focused_window || !scr->focused_window->flags.focused) + window = None; + else + window = scr->focused_window->client_win; + + XChangeProperty(dpy, scr->root_win, net_active_window, XA_WINDOW, 32, + PropModeReplace, (unsigned char*)&window, 1); } static void -updateWorkspaceHint(WWindow *wwin, Bool del) +updateWorkspaceHint(WWindow *wwin, Bool fake, Bool del) { + CARD32 l; + if (del) { - XDeleteProperty(dpy, wwin->client_win, net_wm_desktop); + XDeleteProperty(dpy, wwin->client_win, net_wm_desktop); } else { - XChangeProperty(dpy, wwin->screen_ptr->root_win, - net_wm_desktop, XA_CARDINAL, 32, - PropModeReplace, - (unsigned char*)&wwin->frame->workspace, 1); + l = ((fake || IS_OMNIPRESENT(wwin)) ? -1 : wwin->frame->workspace); + XChangeProperty(dpy, wwin->client_win, net_wm_desktop, XA_CARDINAL, + 32, PropModeReplace, (unsigned char*)&l, 1); } } static void -updateStateHint(WWindow *wwin, Bool del) /* changeable */ +updateStateHint(WWindow *wwin, Bool changedWorkspace, Bool del) /* changeable */ { if (del) { - if (!wwin->flags.net_state_from_client) - XDeleteProperty(dpy, wwin->client_win, net_wm_state); + if (!wwin->flags.net_state_from_client) { + XDeleteProperty(dpy, wwin->client_win, net_wm_state); + } } else { - Atom state[8]; - int i = 0; - - if (wwin->flags.omnipresent) - state[i++] = net_wm_state_sticky; - if (wwin->flags.maximized & MAX_HORIZONTAL) - state[i++] = net_wm_state_maximized_horz; - if (wwin->flags.maximized & MAX_VERTICAL) - state[i++] = net_wm_state_maximized_vert; - if (wwin->flags.shaded) - state[i++] = net_wm_state_shaded; - if (WFLAGP(wwin, skip_window_list) || wwin->flags.net_skip_taskbar) - state[i++] = net_wm_state_skip_taskbar; - if (wwin->flags.net_skip_pager) - state[i++] = net_wm_state_skip_pager; + Atom state[11]; /* nr of defined state atoms */ + int i = 0; + + if(changedWorkspace || (wPreferences.sticky_icons && !IS_OMNIPRESENT(wwin))) + updateWorkspaceHint(wwin, False, False); + + if (IS_OMNIPRESENT(wwin)) + state[i++] = net_wm_state_sticky; + if (wwin->flags.shaded) + state[i++] = net_wm_state_shaded; + if (wwin->flags.maximized & MAX_HORIZONTAL) + state[i++] = net_wm_state_maximized_horz; + if (wwin->flags.maximized & MAX_VERTICAL) + state[i++] = net_wm_state_maximized_vert; + if (WFLAGP(wwin, skip_window_list)) + state[i++] = net_wm_state_skip_taskbar; + if (wwin->flags.net_skip_pager) + state[i++] = net_wm_state_skip_pager; + if ((wwin->flags.hidden || wwin->flags.miniaturized) && !wwin->flags.net_show_desktop){ + state[i++] = net_wm_state_hidden; + state[i++] = net_wm_state_skip_pager; + + if (wwin->flags.miniaturized && wPreferences.sticky_icons) { + if( !IS_OMNIPRESENT(wwin)) + updateWorkspaceHint(wwin, True, False); + state[i++] = net_wm_state_sticky; + } + } + if (WFLAGP(wwin, sunken)) + state[i++] = net_wm_state_below; + if (WFLAGP(wwin, floating)) + state[i++] = net_wm_state_above; + if (wwin->flags.fullscreen) + state[i++] = net_wm_state_fullscreen; + + XChangeProperty(dpy, wwin->client_win, net_wm_state, XA_ATOM, 32, + PropModeReplace, (unsigned char *)state, i); } } -static void +static Bool updateStrut(WWindow *wwin, Bool adding) { - if (adding) { -// XGetWindowProperty(dpy, wwin->client_win, - - /* XXX add property observer */ + WScreen *scr; + WReservedArea *area; + Bool hasState = False; + + scr = wwin->screen_ptr; + + if (adding) { + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + + if (XGetWindowProperty(dpy, wwin->client_win, net_wm_strut, 0, 4, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)==Success && data) { + + area = (WReservedArea *)wmalloc(sizeof(WReservedArea)); + area->area.x1 = data[0]; + area->area.x2 = data[1]; + area->area.y1 = data[2]; + area->area.y2 = data[3]; + + area->window = wwin->client_win; + + area->next = scr->netdata->strut; + scr->netdata->strut = area; + + XFree(data); + hasState = True; +#ifdef VIRTUAL_DESKTOP + /* just in case wm_window_type didn't set it already */ + wwin->client_flags.virtual_stick = 1; +#endif + } + } else { + /* deleting */ + area = scr->netdata->strut; + + if(area) { + if(area->window == wwin->client_win) { + scr->netdata->strut = area->next; + wfree(area); + hasState = True; + } else { + while(area->next && area->next->window != wwin->client_win) + area = area->next; + + if(area->next) { + WReservedArea *next; + + next = area->next->next; + wfree(area->next); + area->next = next; + + hasState = True; + } + } + } + } + + return hasState; +} + + +static int +getWindowLayer(WWindow * wwin) +{ + int layer = WMNormalLevel; + + if (wwin->type == net_wm_window_type_desktop) { + layer = WMDesktopLevel; + } else if (wwin->type == net_wm_window_type_dock) { + layer = WMDockLevel; + } else if (wwin->type == net_wm_window_type_toolbar) { + layer = WMMainMenuLevel; + } else if (wwin->type == net_wm_window_type_menu) { + layer = WMSubmenuLevel; + } else if (wwin->type == net_wm_window_type_utility) { + } else if (wwin->type == net_wm_window_type_splash) { + } else if (wwin->type == net_wm_window_type_dialog) { + if (wwin->transient_for) { + WWindow *parent = wWindowFor(wwin->transient_for); + if (parent && parent->flags.fullscreen) { + layer = WMFullscreenLevel; + } + } + //layer = WMPopUpLevel; + } else if (wwin->type == net_wm_window_type_normal) { + } + + if (wwin->client_flags.sunken && WMSunkenLevel < layer) + layer = WMSunkenLevel; + if (wwin->client_flags.floating && WMFloatingLevel > layer) + layer = WMFloatingLevel; + + return layer; +} + + +static void +doStateAtom(WWindow *wwin, Atom state, int set, Bool init) +{ + + if (state == net_wm_state_sticky) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !IS_OMNIPRESENT(wwin); + } + if (set != wwin->flags.omnipresent) { + wWindowSetOmnipresent(wwin, set); + } + } else if (state == net_wm_state_shaded) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !wwin->flags.shaded; + } + if (init) { + wwin->flags.shaded = set; + } else { + if (set) { + wShadeWindow(wwin); + } else { + wUnshadeWindow(wwin); + } + } + } else if (state == net_wm_state_skip_taskbar) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !wwin->client_flags.skip_window_list; + } + wwin->client_flags.skip_window_list = set; + } else if (state == net_wm_state_skip_pager) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !wwin->flags.net_skip_pager; + } + wwin->flags.net_skip_pager = set; + } else if (state == net_wm_state_maximized_vert) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->flags.maximized & MAX_VERTICAL); + } + if (init) { + wwin->flags.maximized = set; + } else { + if (set) { + wMaximizeWindow(wwin, wwin->flags.maximized | MAX_VERTICAL); + } else { + wMaximizeWindow(wwin, wwin->flags.maximized & ~MAX_VERTICAL); + } + } + } else if (state == net_wm_state_maximized_horz) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->flags.maximized & MAX_HORIZONTAL); + } + if (init) { + wwin->flags.maximized = set; + } else { + if (set) { + wMaximizeWindow(wwin, wwin->flags.maximized | MAX_HORIZONTAL); + } else { + wMaximizeWindow(wwin, wwin->flags.maximized & ~MAX_HORIZONTAL); + } + } + } else if (state == net_wm_state_hidden) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->flags.miniaturized); + } + if (init) { + wwin->flags.miniaturized = set; + } else { + if (set) { + wIconifyWindow(wwin); + } else { + wDeiconifyWindow(wwin); + } + } + } else if (state == net_wm_state_fullscreen) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->flags.fullscreen); + } + if (init) { + wwin->flags.fullscreen = set; + } else { + if (set) { + wFullscreenWindow(wwin); + } else { + wUnfullscreenWindow(wwin); + } + } + } else if (state == net_wm_state_above) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->client_flags.floating); + } + if (init) { + wwin->client_flags.floating = set; + } else { + wwin->client_flags.floating = set; + ChangeStackingLevel(wwin->frame->core, getWindowLayer(wwin)); + } + + } else if (state == net_wm_state_below) { + if (set == _NET_WM_STATE_TOGGLE) { + set = !(wwin->client_flags.sunken); + } + if (init) { + wwin->client_flags.sunken = set; + } else { + wwin->client_flags.sunken = set; + ChangeStackingLevel(wwin->frame->core, getWindowLayer(wwin)); + } + + } else { +#ifdef DEBUG_WMSPEC + printf("doStateAtom unknown atom %s set %d\n", XGetAtomName(dpy, state), set); +#endif } } static void +removeIcon( WWindow * wwin) +{ + if (wwin->icon == NULL) + return; + if (wwin->flags.miniaturized && wwin->icon->mapped) { + XUnmapWindow(dpy, wwin->icon->core->window); + RemoveFromStackList(wwin->icon->core); + wIconDestroy(wwin->icon); + wwin->icon = NULL; + } +} + + +static Bool +handleWindowType(WWindow * wwin, Atom type, int *layer) +{ + Bool ret = True; + + if (type == net_wm_window_type_desktop) { + wwin->client_flags.no_titlebar = 1; + wwin->client_flags.no_resizable = 1; + wwin->client_flags.no_miniaturizable = 1; + wwin->client_flags.no_border = 1; + wwin->client_flags.no_resizebar = 1; + wwin->client_flags.no_shadeable = 1; + wwin->client_flags.no_movable = 1; + wwin->client_flags.omnipresent = 1; + wwin->client_flags.skip_window_list = 1; + wwin->client_flags.dont_move_off = 1; + wwin->client_flags.no_appicon = 1; + wwin->flags.net_skip_pager = 1; + wwin->frame_x = 0; + wwin->frame_y = 0; +#ifdef VIRTUAL_DESKTOP + wwin->client_flags.virtual_stick = 1; +#endif + } else if (type == net_wm_window_type_dock) { + wwin->client_flags.no_titlebar = 1; + wwin->client_flags.no_resizable = 1; + wwin->client_flags.no_miniaturizable = 1; + wwin->client_flags.no_border = 1; /* XXX: really not a single decoration. */ + wwin->client_flags.no_resizebar = 1; + wwin->client_flags.no_shadeable = 1; + wwin->client_flags.no_movable = 1; + wwin->client_flags.omnipresent = 1; + wwin->client_flags.skip_window_list = 1; + wwin->client_flags.dont_move_off = 1; + wwin->flags.net_skip_pager = 1; +#ifdef VIRTUAL_DESKTOP + wwin->client_flags.virtual_stick = 1; +#endif + } else if (type == net_wm_window_type_toolbar) { + wwin->client_flags.no_titlebar = 1; + wwin->client_flags.no_resizable = 1; + wwin->client_flags.no_miniaturizable = 1; + wwin->client_flags.no_resizebar = 1; + wwin->client_flags.no_shadeable = 1; + wwin->client_flags.skip_window_list = 1; + wwin->client_flags.dont_move_off = 1; + wwin->client_flags.no_appicon = 1; + } else if (type == net_wm_window_type_menu) { + wwin->client_flags.no_titlebar = 1; + wwin->client_flags.no_resizable = 1; + wwin->client_flags.no_miniaturizable = 1; + wwin->client_flags.no_resizebar = 1; + wwin->client_flags.no_shadeable = 1; + wwin->client_flags.skip_window_list = 1; + wwin->client_flags.dont_move_off = 1; + wwin->client_flags.no_appicon = 1; + } else if (type == net_wm_window_type_utility) { + wwin->client_flags.no_appicon = 1; + } else if (type == net_wm_window_type_splash) { + wwin->client_flags.no_titlebar = 1; + wwin->client_flags.no_resizable = 1; + wwin->client_flags.no_miniaturizable = 1; + wwin->client_flags.no_resizebar = 1; + wwin->client_flags.no_shadeable = 1; + wwin->client_flags.no_movable = 1; + wwin->client_flags.skip_window_list = 1; + wwin->client_flags.dont_move_off = 1; + wwin->client_flags.no_appicon = 1; + wwin->flags.net_skip_pager = 1; + } else if (type == net_wm_window_type_dialog) { + // wwin->client_flags.skip_window_list = 1; + // wwin->client_flags.no_appicon = 1; + } else if (type == net_wm_window_type_normal) { + } else { + ret = False; + } + + wwin->type = type; + *layer = getWindowLayer(wwin); + + return ret; +} + + +void +wNETWMPositionSplash(WWindow *wwin, int *x, int *y, int width, int height) +{ + if (wwin->type == net_wm_window_type_splash) { + WScreen * scr = wwin->screen_ptr; + WMRect rect = wGetRectForHead(scr, wGetHeadForPointerLocation(scr)); + *x = rect.pos.x + (rect.size.width - width)/2; + *y = rect.pos.y + (rect.size.height - height)/2; + } +} + + +static void +updateWindowType(WWindow * wwin) +{ + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + int layer; + if (XGetWindowProperty(dpy, wwin->client_win, net_wm_window_type, 0, 1, + False, XA_ATOM, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, (unsigned char **)&data)==Success + && data) { + + int i; + Atom * type = (Atom *)data; + for (i=0; iframe->core, layer); + wwin->frame->flags.need_texture_change = 1; + wWindowConfigureBorders(wwin); + wFrameWindowPaint(wwin->frame); + wNETWMUpdateActions(wwin, False); +} + + +Bool +wNETWMCheckClientHints(WWindow *wwin, int *layer, int *workspace) +{ + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + Bool hasState = False; + int i; + + if (XGetWindowProperty(dpy, wwin->client_win, net_wm_desktop, 0, 1, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)==Success && data) { + + long desktop = *data; + XFree(data); + + if(desktop == -1) + wwin->client_flags.omnipresent = 1; + else + *workspace = desktop; + + hasState = True; + } + + if (XGetWindowProperty(dpy, wwin->client_win, net_wm_state, 0, 1, False, + XA_ATOM, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)==Success && data) { + + Atom * state = (Atom *)data; + for(i=0; iclient_win, net_wm_window_type, 0, 1, False, + XA_ATOM, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char **)&data) == Success && data) { + + Atom * type = (Atom *)data; + for (i=0; iscreen_ptr); + + return hasState; +} + + +static Bool +updateNetIconInfo(WWindow *wwin) { + + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + Bool hasState = False; + Bool old_state = wwin->flags.net_handle_icon; + + if (XGetWindowProperty(dpy, wwin->client_win, net_wm_handled_icons, 0, 1, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, (unsigned char **)&data) == Success && data) { + long handled = *data; + wwin->flags.net_handle_icon = (handled != 0); + XFree(data); + hasState = True; + + } else wwin->flags.net_handle_icon = False; + + if ( XGetWindowProperty(dpy, wwin->client_win, net_wm_icon_geometry, 0, 4, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, (unsigned char **)&data) == Success && data) { + +#ifdef NETWM_PROPER + if (wwin->flags.net_handle_icon) +#else + wwin->flags.net_handle_icon = True; +#endif + { + wwin->icon_x = data[0]; + wwin->icon_y = data[1]; + wwin->icon_w = data[2]; + wwin->icon_h = data[3]; + } + + XFree(data); + hasState = True; + + } else wwin->flags.net_handle_icon = False; + + if (wwin->flags.miniaturized && + old_state != wwin->flags.net_handle_icon) { + if (wwin->flags.net_handle_icon) { + removeIcon(wwin); + } else { + wwin->flags.miniaturized = False; + wwin->flags.skip_next_animation = True; + wIconifyWindow(wwin); + } + } + + return hasState; +} + + +Bool +wNETWMCheckInitialClientState(WWindow *wwin) +{ + Bool hasState = False; + +#ifdef DEBUG_WMSPEC + printf("CheckInitialClientState\n"); +#endif + + wNETWMShowingDesktop(wwin->screen_ptr, False); + + hasState |= updateNetIconInfo(wwin); + + updateIconImage(wwin->screen_ptr, wwin); + + return hasState; +} + + +static void +handleDesktopNames(XClientMessageEvent *event, WScreen *scr) +{ + unsigned long nitems_ret, bytes_after_ret; + char *data, *names[32]; + int fmt_ret, i, n; + Atom type_ret; + + if (XGetWindowProperty(dpy, scr->root_win, net_desktop_names, 0, 1, False, + utf8_string, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)!=Success) { + return; + } + + if (data == 0) + return; + + if (type_ret != utf8_string || fmt_ret != 8) + return; + + n = 0; + names[n] = data; + for (i = 0; i < nitems_ret; i++) { + if (data[i] == 0) { + n++; + names[n] = &data[i]; + } else if (*names[n] == 0) { + names[n] = &data[i]; + wWorkspaceRename(scr, n, names[n]); + } + } +} + + +Bool +wNETWMProcessClientMessage(XClientMessageEvent *event) +{ + WScreen *scr; + WWindow *wwin; + Bool done = True; + +#ifdef DEBUG_WMSPEC + printf("processClientMessage type %s\n", XGetAtomName(dpy, event->message_type)); +#endif + + scr = wScreenForWindow(event->window); + if (scr) { + /* generic client messages */ + if (event->message_type == net_current_desktop) { + wWorkspaceChange(scr, event->data.l[0]); + } else if(event->message_type == net_number_of_desktops) { + long value; + + value = event->data.l[0]; + if(value > scr->workspace_count) { + wWorkspaceMake(scr, value - scr->workspace_count); + } else if(value < scr->workspace_count) { + int i; + Bool rebuild = False; + + for (i = scr->workspace_count-1; i >= value; i--) { + if (!wWorkspaceDelete(scr, i)) { + rebuild = True; + break; + } + } + + if(rebuild) { + updateWorkspaceCount(scr); + } + } + } else if (event->message_type == net_showing_desktop) { + wNETWMShowingDesktop(scr, event->data.l[0]); +#ifdef VIRTUAL_DESKTOP + } else if (event->message_type == net_desktop_viewport) { + wWorkspaceSetViewPort(scr, scr->current_workspace, + event->data.l[0], event->data.l[1]); +#endif + } else if (event->message_type == net_desktop_names) { + handleDesktopNames(event, scr); + } else { + done = False; + } + + if (done) + return True; + } + + /* window specific client messages */ + + wwin = wWindowFor(event->window); + if (!wwin) + return False; + + if (event->message_type == net_active_window) { + wNETWMShowingDesktop(scr, False); + wMakeWindowVisible(wwin); + } else if (event->message_type == net_close_window) { + if (!WFLAGP(wwin, no_closable)) { + if (wwin->protocols.DELETE_WINDOW) + wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp); + } + } else if (event->message_type == net_wm_state) { + int maximized = wwin->flags.maximized; + long set = event->data.l[0]; + +#ifdef DEBUG_WMSPEC + printf("net_wm_state set %d a1 %s a2 %s\n", set, + XGetAtomName(dpy, event->data.l[1]), + XGetAtomName(dpy, event->data.l[2])); +#endif + + doStateAtom(wwin, (Atom)event->data.l[1], set, False); + if(event->data.l[2]) + doStateAtom(wwin, (Atom)event->data.l[2], set, False); + + if(wwin->flags.maximized != maximized) { + if(!wwin->flags.maximized) { + wwin->flags.maximized = maximized; + wUnmaximizeWindow(wwin); + } else { + wMaximizeWindow(wwin, wwin->flags.maximized); + } + } + updateStateHint(wwin, False, False); + } else if (event->message_type == net_wm_handled_icons || + event->message_type == net_wm_icon_geometry) { + updateNetIconInfo(wwin); + } else if (event->message_type == net_wm_desktop) { + long desktop = event->data.l[0]; + if (desktop == -1) { + wWindowSetOmnipresent(wwin, True); + } else { + if (IS_OMNIPRESENT(wwin)) + wWindowSetOmnipresent(wwin, False); + wWindowChangeWorkspace(wwin, desktop); + } + } else if (event->message_type == net_wm_icon) { + updateIconImage(scr, wwin); + } else { + done = False; + } + + return done; +} + + +Bool +wNETWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event) +{ + Bool ret = True; + + if(event->atom == net_wm_strut) { + updateStrut(wwin, False); + updateStrut(wwin, True); + wScreenUpdateUsableArea(wwin->screen_ptr); + } else if (event->atom == net_wm_handled_icons || + event->atom == net_wm_icon_geometry) { + updateNetIconInfo(wwin); + } else if (event->atom == net_wm_window_type) { + updateWindowType(wwin); + } else { + ret = False; + } + + return ret; +} + + +int +wNETWMGetPidForWindow(Window window) +{ + Atom type_ret; + int fmt_ret; + unsigned long nitems_ret; + unsigned long bytes_after_ret; + long *data = 0; + int pid; + + if (XGetWindowProperty(dpy, window, net_wm_pid, 0, 1, False, + XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, + &bytes_after_ret, + (unsigned char**)&data)==Success && data) { + + pid = *data; + XFree(data); + } else { + pid = 0; + } + + return pid; +} + + +static void observer(void *self, WMNotification *notif) { WWindow *wwin = (WWindow*)WMGetNotificationObject(notif); const char *name = WMGetNotificationName(notif); void *data = WMGetNotificationClientData(notif); NetData *ndata = (NetData*)self; - - + + if (strcmp(name, WMNManaged) == 0 && wwin) { - updateClientList(wwin->screen_ptr, wwin, True); - - updateStrut(wwin, True); + updateClientList(wwin->screen_ptr); + updateClientListStacking(wwin->screen_ptr, NULL); + updateStateHint(wwin, True, False); + updateStrut(wwin, False); + updateStrut(wwin, True); + wScreenUpdateUsableArea(wwin->screen_ptr); } else if (strcmp(name, WMNUnmanaged) == 0 && wwin) { - updateClientList(wwin->screen_ptr, wwin, False); - updateWorkspaceHint(wwin, True); - updateStateHint(wwin, True); - - updateStrut(wwin, False); - + updateClientList(wwin->screen_ptr); + updateClientListStacking(wwin->screen_ptr, wwin); + updateWorkspaceHint(wwin, False, True); + updateStateHint(wwin, False, True); + wNETWMUpdateActions(wwin, True); + + updateStrut(wwin, False); + wScreenUpdateUsableArea(wwin->screen_ptr); } else if (strcmp(name, WMNResetStacking) == 0 && wwin) { - updateClientListStacking(wwin->screen_ptr); - + updateClientListStacking(wwin->screen_ptr, NULL); + updateStateHint(wwin, False, False); } else if (strcmp(name, WMNChangedStacking) == 0 && wwin) { - updateClientListStacking(wwin->screen_ptr); - + updateClientListStacking(wwin->screen_ptr, NULL); + updateStateHint(wwin, False, False); } else if (strcmp(name, WMNChangedFocus) == 0) { - updateFocusHint(ndata->scr, wwin); - + updateFocusHint(ndata->scr, wwin); } else if (strcmp(name, WMNChangedWorkspace) == 0 && wwin) { - updateWorkspaceHint(wwin, False); - + updateWorkspaceHint(wwin, False, False); + updateStateHint(wwin, True, False); } else if (strcmp(name, WMNChangedState) == 0 && wwin) { - updateStateHint(wwin, False); + updateStateHint(wwin, !strcmp(data, "omnipresent"), False); } } @@ -439,18 +1565,21 @@ wsobserver(void *self, WMNotification *notif) { WScreen *scr = (WScreen*)WMGetNotificationObject(notif); const char *name = WMGetNotificationName(notif); - void *data = WMGetNotificationClientData(notif); + //void *data = WMGetNotificationClientData(notif); if (strcmp(name, WMNWorkspaceCreated) == 0) { - updateWorkspaceCount(scr); + updateWorkspaceCount(scr); + updateWorkspaceNames(scr); } else if (strcmp(name, WMNWorkspaceDestroyed) == 0) { - updateWorkspaceCount(scr); + updateWorkspaceCount(scr); + updateWorkspaceNames(scr); } else if (strcmp(name, WMNWorkspaceChanged) == 0) { - updateCurrentWorkspace(scr); + updateCurrentWorkspace(scr); } else if (strcmp(name, WMNWorkspaceNameChanged) == 0) { - updateWorkspaceNames(scr, (int)data); + updateWorkspaceNames(scr); } } +#endif /* NETWM_HINTS */ diff --git a/src/wmspec.h b/src/wmspec.h index b4294fe9..39890875 100644 --- a/src/wmspec.h +++ b/src/wmspec.h @@ -25,6 +25,21 @@ #ifndef _WMSPEC_H_ #define _WMSPEC_H_ +#include +#include +#include +void wNETWMInitStuff(WScreen *scr); +void wNETWMUpdateWorkarea(WScreen *scr, WArea usableArea); +Bool wNETWMGetUsableArea(WScreen *scr, int head, WArea *area); +Bool wNETWMCheckInitialClientState(WWindow *wwin); +Bool wNETWMProcessClientMessage(XClientMessageEvent *event); +Bool wNETWMCheckClientHints(WWindow *wwin, int *layer, int *workspace); +Bool wNETWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event); +void wNETWMShowingDesktop(WScreen *scr, Bool show); +void wNETWMUpdateActions(WWindow *wwin, Bool del); +void wNETWMUpdateDesktop(WScreen *scr); +void wNETWMPositionSplash(WWindow *wwin, int *x, int *y, int width, int height); +int wNETWMGetPidForWindow(Window window); #endif diff --git a/src/workspace.c b/src/workspace.c index 2e1387bf..85cb2281 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -16,7 +16,7 @@ * * 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, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "wconfig.h" @@ -33,6 +33,7 @@ #include #include #include +#include #include "WindowMaker.h" #include "wcore.h" @@ -49,11 +50,18 @@ #ifdef KWM_HINTS #include "kwm.h" #endif +#ifdef NETWM_HINTS +#include "wmspec.h" +#endif + +#include "xinerama.h" extern WPreferences wPreferences; extern XContext wWinContext; +extern XContext wVEdgeContext; +extern void ProcessPendingEvents(); static WMPropList *dWorkspaces=NULL; static WMPropList *dClip, *dName; @@ -62,6 +70,7 @@ static WMPropList *dClip, *dName; static BOOL initVDesk = False; #endif + static void make_keys() { @@ -91,55 +100,59 @@ wWorkspaceNew(WScreen *scr) int i; if (scr->workspace_count < MAX_WORKSPACES) { - scr->workspace_count++; + scr->workspace_count++; - wspace = wmalloc(sizeof(WWorkspace)); - wspace->name = NULL; + wspace = wmalloc(sizeof(WWorkspace)); + wspace->name = NULL; #ifdef KWM_HINTS - if (scr->flags.kwm_syncing_count) { - wspace->name = wKWMGetWorkspaceName(scr, scr->workspace_count-1); - } + if (scr->flags.kwm_syncing_count) { + wspace->name = wKWMGetWorkspaceName(scr, scr->workspace_count-1); + } #endif - if (!wspace->name) { - wspace->name = wmalloc(strlen(_("Workspace %i"))+8); - sprintf(wspace->name, _("Workspace %i"), scr->workspace_count); - } + if (!wspace->name) { + wspace->name = wmalloc(strlen(_("Workspace %i"))+8); + sprintf(wspace->name, _("Workspace %i"), scr->workspace_count); + } - if (!wPreferences.flags.noclip) { - wspace->clip = wDockCreate(scr, WM_CLIP); - } else - wspace->clip = NULL; + if (!wPreferences.flags.noclip) { + wspace->clip = wDockCreate(scr, WM_CLIP); + } else + wspace->clip = NULL; - list = wmalloc(sizeof(WWorkspace*)*scr->workspace_count); + list = wmalloc(sizeof(WWorkspace*)*scr->workspace_count); - for (i=0; iworkspace_count-1; i++) { - list[i] = scr->workspaces[i]; - } - list[i] = wspace; - if (scr->workspaces) - wfree(scr->workspaces); - scr->workspaces = list; + for (i=0; iworkspace_count-1; i++) { + list[i] = scr->workspaces[i]; + } + list[i] = wspace; + if (scr->workspaces) + wfree(scr->workspaces); + scr->workspaces = list; - wWorkspaceMenuUpdate(scr, scr->workspace_menu); - wWorkspaceMenuUpdate(scr, scr->clip_ws_menu); + wWorkspaceMenuUpdate(scr, scr->workspace_menu); + wWorkspaceMenuUpdate(scr, scr->clip_ws_menu); #ifdef VIRTUAL_DESKTOP - wspace->view_x = wspace->view_y = 0; - wspace->height = scr->scr_height; - wspace->width = scr->scr_width; + wspace->view_x = wspace->view_y = 0; + wspace->height = scr->scr_height; + wspace->width = scr->scr_width; +#endif +#ifdef NETWM_HINTS + wNETWMUpdateDesktop(scr); #endif - WMPostNotificationName(WMNWorkspaceCreated, scr, - (void*)(scr->workspace_count-1)); - XFlush(dpy); - return scr->workspace_count-1; + WMPostNotificationName(WMNWorkspaceCreated, scr, + (void*)(scr->workspace_count-1)); + XFlush(dpy); + + return scr->workspace_count-1; } + return -1; } - Bool wWorkspaceDelete(WScreen *scr, int workspace) { @@ -147,7 +160,6 @@ wWorkspaceDelete(WScreen *scr, int workspace) WWorkspace **list; int i, j; - if (workspace<=0) return False; @@ -167,9 +179,9 @@ wWorkspaceDelete(WScreen *scr, int workspace) list = wmalloc(sizeof(WWorkspace*)*(scr->workspace_count-1)); j = 0; for (i=0; iworkspace_count; i++) { - if (i!=workspace) + if (i!=workspace) { list[j++] = scr->workspaces[i]; - else { + } else { if (scr->workspaces[i]->name) wfree(scr->workspaces[i]->name); wfree(scr->workspaces[i]); @@ -205,6 +217,10 @@ wWorkspaceDelete(WScreen *scr, int workspace) wMenuRealize(menu); } +#ifdef NETWM_HINTS + wNETWMUpdateDesktop(scr); +#endif + WMPostNotificationName(WMNWorkspaceDestroyed, scr, (void*)(scr->workspace_count-1)); @@ -223,7 +239,6 @@ typedef struct WorkspaceNameData { } WorkspaceNameData; - static void hideWorkspaceName(void *data) { @@ -246,8 +261,7 @@ hideWorkspaceName(void *data) Pixmap pix; scr->workspace_name_timer = - WMAddTimerHandler(WORKSPACE_NAME_FADE_DELAY, hideWorkspaceName, - scr); + WMAddTimerHandler(WORKSPACE_NAME_FADE_DELAY, hideWorkspaceName, scr); RCombineImagesWithOpaqueness(img, scr->workspace_name_data->text, scr->workspace_name_data->count*255/10); @@ -266,7 +280,6 @@ hideWorkspaceName(void *data) } - static void showWorkspaceName(WScreen *scr, int workspace) { @@ -279,9 +292,10 @@ showWorkspaceName(WScreen *scr, int workspace) int len = strlen(name); int x, y; - if (wPreferences.workspace_name_display_position == WD_NONE - || scr->workspace_count < 2) - return; + if (wPreferences.workspace_name_display_position == WD_NONE || + scr->workspace_count < 2) { + return; + } if (scr->workspace_name_timer) { WMDeleteTimerHandler(scr->workspace_name_timer); @@ -298,6 +312,7 @@ showWorkspaceName(WScreen *scr, int workspace) } data = wmalloc(sizeof(WorkspaceNameData)); + data->back = NULL; w = WMWidthOfString(scr->workspace_name_font, name, len); h = WMFontHeight(scr->workspace_name_font); @@ -347,7 +362,7 @@ showWorkspaceName(WScreen *scr, int workspace) for (x = 0; x <= 4; x++) { for (y = 0; y <= 4; y++) { WMDrawString(scr->wmscreen, text, scr->white, - scr->workspace_name_font, x, y, name, len); + scr->workspace_name_font, x, y, name, len); } } @@ -404,7 +419,7 @@ showWorkspaceName(WScreen *scr, int workspace) /* set a timeout for the effect */ data->timeout = time(NULL) + 2 + - (WORKSPACE_NAME_DELAY + WORKSPACE_NAME_FADE_DELAY*data->count)/1000; + (WORKSPACE_NAME_DELAY + WORKSPACE_NAME_FADE_DELAY*data->count)/1000; scr->workspace_name_data = data; @@ -452,25 +467,23 @@ wWorkspaceRelativeChange(WScreen *scr, int amount) w = scr->current_workspace + amount; if (amount < 0) { - - if (w >= 0) + if (w >= 0) { wWorkspaceChange(scr, w); - else if (wPreferences.ws_cycle) + } else if (wPreferences.ws_cycle) { wWorkspaceChange(scr, scr->workspace_count + w); - + } } else if (amount > 0) { - - if (w < scr->workspace_count) + if (w < scr->workspace_count) { wWorkspaceChange(scr, w); - else if (wPreferences.ws_advance) + } else if (wPreferences.ws_advance) { wWorkspaceChange(scr, WMIN(w, MAX_WORKSPACES-1)); - else if (wPreferences.ws_cycle) - wWorkspaceChange(scr, w % scr->workspace_count); + } else if (wPreferences.ws_cycle) { + wWorkspaceChange(scr, w % scr->workspace_count); + } } } - void wWorkspaceForceChange(WScreen *scr, int workspace) { @@ -494,29 +507,24 @@ wWorkspaceForceChange(WScreen *scr, int workspace) wWorkspaceMenuUpdate(scr, scr->clip_ws_menu); if ((tmp = scr->focused_window)!= NULL) { - if ((IS_OMNIPRESENT(tmp) && (tmp->flags.mapped || tmp->flags.shaded) - && !WFLAGP(tmp, no_focusable)) - || tmp->flags.changing_workspace) { + if ((IS_OMNIPRESENT(tmp) && (tmp->flags.mapped || tmp->flags.shaded) && + !WFLAGP(tmp, no_focusable)) || tmp->flags.changing_workspace) { foc = tmp; } /* foc2 = tmp; will fix annoyance with gnome panel * but will create annoyance for every other application */ - while (tmp) { if (tmp->frame->workspace!=workspace && !tmp->flags.selected) { /* unmap windows not on this workspace */ - if ((tmp->flags.mapped||tmp->flags.shaded) - && !IS_OMNIPRESENT(tmp) - && !tmp->flags.changing_workspace) { - + if ((tmp->flags.mapped||tmp->flags.shaded) && + !IS_OMNIPRESENT(tmp) && !tmp->flags.changing_workspace) { wWindowUnmap(tmp); } /* also unmap miniwindows not on this workspace */ if (!wPreferences.sticky_icons && tmp->flags.miniaturized && tmp->icon && !IS_OMNIPRESENT(tmp)) { - XUnmapWindow(dpy, tmp->icon->core->window); tmp->icon->mapped = 0; } @@ -529,8 +537,9 @@ wWorkspaceForceChange(WScreen *scr, int workspace) if (wapp) { wapp->last_workspace = workspace; } - if (!foc2 && (tmp->flags.mapped || tmp->flags.shaded)) - foc2 = tmp; + if (!foc2 && (tmp->flags.mapped || tmp->flags.shaded)) { + foc2 = tmp; + } } } else { /* change selected windows' workspace */ @@ -544,8 +553,9 @@ wWorkspaceForceChange(WScreen *scr, int workspace) if (!(tmp->flags.mapped || tmp->flags.miniaturized)) { /* remap windows that are on this workspace */ wWindowMap(tmp); - if (!foc && !WFLAGP(tmp, no_focusable)) - foc = tmp; + if (!foc && !WFLAGP(tmp, no_focusable)) { + foc = tmp; + } } /* Also map miniwindow if not omnipresent */ if (!wPreferences.sticky_icons && @@ -560,6 +570,16 @@ wWorkspaceForceChange(WScreen *scr, int workspace) tmp = tmp->prev; } + /* Gobble up events unleashed by our mapping & unmapping. + * These may trigger various grab-initiated focus & + * crossing events. However, we don't care about them, + * and ignore their focus implications altogether to avoid + * flicker. + */ + scr->flags.ignore_focus_events = 1; + ProcessPendingEvents(); + scr->flags.ignore_focus_events = 0; + if (!foc) foc = foc2; @@ -577,13 +597,19 @@ wWorkspaceForceChange(WScreen *scr, int workspace) tmp = NULL; if (XQueryPointer(dpy, scr->root_win, &bar, &win, &foo, &foo, &foo, &foo, &mask)) { - tmp = wWindowFor(win); - } - if (!tmp && wPreferences.focus_mode == WKF_SLOPPY) { - wSetFocusTo(scr, foc); - } else { - wSetFocusTo(scr, tmp); - } + tmp = wWindowFor(win); + } + + /* If there's a window under the pointer, focus it. + * (we ate all other focus events above, so it's + * certainly not focused). Otherwise focus last + * focused, or the root (depending on sloppiness) + */ + if (!tmp && wPreferences.focus_mode == WKF_SLOPPY) { + wSetFocusTo(scr, foc); + } else { + wSetFocusTo(scr, tmp); + } } } @@ -609,9 +635,12 @@ wWorkspaceForceChange(WScreen *scr, int workspace) } } -#ifdef KWM_HINTS +#if defined KWM_HINTS || defined NETWM_HINTS wScreenUpdateUsableArea(scr); #endif +#ifdef NETWM_HINTS + wNETWMUpdateDesktop(scr); +#endif showWorkspaceName(scr, workspace); @@ -620,23 +649,320 @@ wWorkspaceForceChange(WScreen *scr, int workspace) /* XSync(dpy, False); */ } + #ifdef VIRTUAL_DESKTOP + /* TODO: -* 1) Allow border around each window so the scrolling -* won't just stop at the border. -* 2) Make pager. -*/ + * + * 1) Allow border around each window so the scrolling + * won't just stop at the border. + * 2) Make pager. + * + */ + +#define vec_sub(a, b) wmkpoint((a).x-(b).x, (a).y-(b).y) +#define vec_add(a, b) wmkpoint((a).x+(b).x, (a).y+(b).y) +#define vec_inc(a, b) do { (a).x+=(b).x; (a).y+=(b).y; } while(0) +#define vec_dot(a, b) ((a).x*(b).x + (a).y*(b).y) +#define vec_scale(a, s) wmkpoint((a).x*s, (a).y*s) +#define vec_scale2(a, s, t) wmkpoint((a).x*s, (a).y*t) + +#ifndef HAS_BORDER +#define HAS_BORDER(w) (!(WFLAGP((w), no_border))) +#endif + +#ifndef IS_VSTUCK +#define IS_VSTUCK(w) (WFLAGP((w), virtual_stick)) +#endif + +#define updateMinimum(l,p,ml,mp) do { if (cmp(l) && (l)<(ml)) { (ml)=(l); (mp)=(p); }; } while(0) + +static Bool cmp_gez(int i) { return (i >= 0); } + +static Bool cmp_gz(int i) { return (i > 0); } + + +static WMPoint +getClosestEdge(WScreen * scr, WMPoint direction, Bool (*cmp)(int)) +{ + WMPoint closest = wmkpoint(0, 0); + int closest_len = INT_MAX; + WWindow * wwin; + + for (wwin=scr->focused_window; wwin; wwin=wwin->prev) { + if (wwin->frame->workspace == scr->current_workspace) { + if (!wwin->flags.miniaturized && + !IS_VSTUCK(wwin) && + !wwin->flags.hidden) { + int border = 2*HAS_BORDER(wwin); + int len; + int x1,x2,y1,y2; + int head = wGetHeadForWindow(wwin); + WArea area = wGetUsableAreaForHead(scr, head, NULL, False); + WMPoint p; + + x1 = wwin->frame_x - area.x1; + y1 = wwin->frame_y - area.y1; + x2 = wwin->frame_x + wwin->frame->core->width + border - area.x2; + y2 = wwin->frame_y + wwin->frame->core->height + border - area.y2; + + p = wmkpoint(x1,y1); + len = vec_dot(direction, p); + updateMinimum(len, p, closest_len, closest); + + p = wmkpoint(x1,y2); + len = vec_dot(direction, p); + updateMinimum(len, p, closest_len, closest); + + p = wmkpoint(x2,y1); + len = vec_dot(direction, p); + updateMinimum(len, p, closest_len, closest); + + p = wmkpoint(x2,y2); + len = vec_dot(direction, p); + updateMinimum(len, p, closest_len, closest); + } + } + } + + return closest; +} + + +void +wWorkspaceKeyboardMoveDesktop(WScreen *scr, WMPoint direction) +{ + int x, y; + WMPoint edge = getClosestEdge(scr, direction, cmp_gz); + int len = vec_dot(edge, direction); + WMPoint step = vec_scale(direction, len); + wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); + wWorkspaceSetViewPort(scr, scr->current_workspace, x+step.x, y+step.y); +} + + +extern Cursor wCursor[WCUR_LAST]; + + +static void +vdMouseMoveDesktop(XEvent *event, WMPoint direction) +{ + static int lock = False; + if (lock) return; + lock = True; + + Bool done = False; + Bool moved = True; + WScreen *scr = wScreenForRootWindow(event->xcrossing.root); + WMPoint old_pos = wmkpoint(event->xcrossing.x_root, event->xcrossing.y_root); + WMPoint step; + int x, y; + int resisted = 0; + + if (XGrabPointer(dpy, event->xcrossing.window, False, + PointerMotionMask, GrabModeAsync, GrabModeAsync, + scr->root_win, wCursor[WCUR_EMPTY], + CurrentTime) != GrabSuccess) { + + /* if the grab fails, do it the old fashioned way */ + step = vec_scale2(direction, wPreferences.vedge_hscrollspeed, + wPreferences.vedge_vscrollspeed); + wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); + if (wWorkspaceSetViewPort(scr, scr->current_workspace, + x+step.x, y+step.y)) { + step = vec_scale(direction, wPreferences.vedge_thickness + 1); + XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, + event->xcrossing.x_root - step.x, + event->xcrossing.y_root - step.y); + } + goto exit; + } + XSync(dpy, True); + + if (old_pos.x < 0) + old_pos.x = 0; + if (old_pos.y < 0) + old_pos.y = 0; + if (old_pos.x > scr->scr_width) + old_pos.x = scr->scr_width; + if (old_pos.y > scr->scr_height) + old_pos.y = scr->scr_height; + + while (!done) { + XEvent ev; + if (moved) { + XWarpPointer(dpy, None, scr->root_win, 0, 0, 0, 0, + scr->scr_width/2, scr->scr_height/2); + moved = False; + } + WMMaskEvent(dpy, PointerMotionMask, &ev); + + switch (ev.type) { + case MotionNotify: + { + int step_len; + step = wmkpoint(ev.xmotion.x_root-scr->scr_width/2, + ev.xmotion.y_root-scr->scr_height/2); + step_len = vec_dot(step, direction); + if (step_len < 0) { + done = True; + break; + } + + if (step_len > 0) { + Bool do_move = True; + int resist = wPreferences.vedge_resistance; + WMPoint closest; + int closest_len = INT_MAX; + if (resist) { + closest = getClosestEdge(scr, direction, cmp_gez); + closest_len = vec_dot(direction, closest); + } + + if (!closest_len) { + resisted += step_len; + do_move = resisted >= resist; + if (do_move) { + closest_len = INT_MAX; + step_len = resisted - resist; + resisted = 0; + } + } + if (do_move) { + if (closest_len <= wPreferences.vedge_attraction) { + step = vec_scale(direction, closest_len); + } else { + step = vec_scale(direction, step_len); + } + + wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); + wWorkspaceSetViewPort(scr, scr->current_workspace, + x+step.x, y+step.y); + moved = True; + } + } + } + break; + } + } + + step = vec_add(old_pos, vec_scale(direction, -1)); + XWarpPointer(dpy, None, scr->root_win, 0,0,0,0, step.x, step.y); + XUngrabPointer(dpy, CurrentTime); + +exit: + lock = False; +} + + +static void +vdHandleEnter_u(XEvent *event) { + vdMouseMoveDesktop(event, VEC_UP); +} + + +static void +vdHandleEnter_d(XEvent *event) { + vdMouseMoveDesktop(event, VEC_DOWN); +} + + +static void +vdHandleEnter_l(XEvent *event) { + vdMouseMoveDesktop(event, VEC_LEFT); +} + + +static void +vdHandleEnter_r(XEvent *event) { + vdMouseMoveDesktop(event, VEC_RIGHT); +} + + +static void +wWorkspaceMapEdge(WScreen *scr) +{ + int i; + if (wPreferences.vedge_thickness && initVDesk) { + for (i=0; ivirtual_nr_edges; ++i) { + XMapWindow(dpy, scr->virtual_edges[i]); + } + } +} + + +static void +wWorkspaceUnmapEdge(WScreen *scr) +{ + int i; + if (wPreferences.vedge_thickness && initVDesk) { + for (i=0; ivirtual_nr_edges; ++i) { + XUnmapWindow(dpy, scr->virtual_edges[i]); + } + } +} + + +#define LEFT_EDGE 0x01 +#define RIGHT_EDGE 0x02 +#define TOP_EDGE 0x04 +#define BOTTOM_EDGE 0x08 +#define ALL_EDGES 0x0F void wWorkspaceManageEdge(WScreen *scr) { - int w; - int vmask; - XSetWindowAttributes attribs; + if (!initVDesk && wPreferences.vedge_thickness) { + int i, j, w; + int vmask; + XSetWindowAttributes attribs; + + int heads = wXineramaHeads(scr); + int *hasEdges = (int*)wmalloc(sizeof(int)*heads); + + int thickness = wPreferences.vedge_thickness; + int nr_edges = 0; + int max_edges = 4*heads; + int head; + Window * edges = (Window *)wmalloc(sizeof(Window)*max_edges); - /* puts("wWorkspaceManageEdge()"); */ - if (wPreferences.vedge_thickness) { initVDesk = True; + + for (i=0; i 0 && hlen == 0) { /* horz alignment, vert edges touch */ + if (i_rect.pos.x < j_rect.pos.x) { /* i left of j */ + hasEdges[i] &= ~RIGHT_EDGE; + hasEdges[j] &= ~LEFT_EDGE; + } else { /* j left of i */ + hasEdges[j] &= ~RIGHT_EDGE; + hasEdges[i] &= ~LEFT_EDGE; + } + } else if (vlen == 0 && hlen > 0) { /* vert alignment, horz edges touch */ + if (i_rect.pos.y < j_rect.pos.y) { /* i top of j */ + hasEdges[i] &= ~BOTTOM_EDGE; + hasEdges[j] &= ~TOP_EDGE; + } else { /* j top of i */ + hasEdges[j] &= ~BOTTOM_EDGE; + hasEdges[i] &= ~TOP_EDGE; + } + } + } + } + for (w = 0; w < scr->workspace_count; w++) { /* puts("reset workspace"); */ wWorkspaceSetViewPort(scr, w, 0, 0); @@ -645,93 +971,202 @@ wWorkspaceManageEdge(WScreen *scr) vmask = CWEventMask|CWOverrideRedirect; attribs.event_mask = (EnterWindowMask | LeaveWindowMask | VisibilityChangeMask); attribs.override_redirect = True; - scr->virtual_edge_u = - XCreateWindow(dpy, scr->root_win, 0, 0, - scr->scr_width, wPreferences.vedge_thickness, 0, - CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs); - scr->virtual_edge_d = - XCreateWindow(dpy, scr->root_win, 0, scr->scr_height-wPreferences.vedge_thickness, - scr->scr_width, wPreferences.vedge_thickness, 0, - CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs); - scr->virtual_edge_l = - XCreateWindow(dpy, scr->root_win, 0, 0, - wPreferences.vedge_thickness, scr->scr_height, 0, - CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs); - scr->virtual_edge_r = - XCreateWindow(dpy, scr->root_win, scr->scr_width-wPreferences.vedge_thickness, 0, - wPreferences.vedge_thickness, scr->scr_height, 0, - CopyFromParent, InputOnly, CopyFromParent, vmask, &attribs); - XMapWindow(dpy, scr->virtual_edge_u); - XMapWindow(dpy, scr->virtual_edge_d); - XMapWindow(dpy, scr->virtual_edge_l); - XMapWindow(dpy, scr->virtual_edge_r); + + for (head=0; headroot_win, rect.pos.x, rect.pos.y, + rect.size.width, thickness, 0, + CopyFromParent, InputOnly, CopyFromParent, + vmask, &attribs); + XSaveContext(dpy, edges[nr_edges], wVEdgeContext, + (XPointer)vdHandleEnter_u); + ++nr_edges; + } + + if (hasEdges[head] & BOTTOM_EDGE) { + edges[nr_edges] = + XCreateWindow(dpy, scr->root_win, rect.pos.x, + rect.pos.y+rect.size.height-thickness, + rect.size.width, thickness, 0, + CopyFromParent, InputOnly, CopyFromParent, + vmask, &attribs); + XSaveContext(dpy, edges[nr_edges], wVEdgeContext, + (XPointer)vdHandleEnter_d); + ++nr_edges; + } + + if (hasEdges[head] & LEFT_EDGE) { + edges[nr_edges] = + XCreateWindow(dpy, scr->root_win, rect.pos.x, rect.pos.y, + thickness, rect.pos.y+rect.size.height, 0, + CopyFromParent, InputOnly, CopyFromParent, + vmask, &attribs); + XSaveContext(dpy, edges[nr_edges], wVEdgeContext, + (XPointer)vdHandleEnter_l); + ++nr_edges; + } + + if (hasEdges[head] & RIGHT_EDGE) { + edges[nr_edges] = + XCreateWindow(dpy, scr->root_win, + rect.pos.x + rect.size.width - thickness, rect.pos.y, + thickness, rect.size.height, 0, + CopyFromParent, InputOnly, CopyFromParent, vmask, + &attribs); + XSaveContext(dpy, edges[nr_edges], wVEdgeContext, + (XPointer)vdHandleEnter_r); + ++nr_edges; + } + } + + scr->virtual_nr_edges = nr_edges; + scr->virtual_edges = edges; + + wWorkspaceMapEdge(scr); wWorkspaceRaiseEdge(scr); + + wfree(hasEdges); + } +} + + +void +wWorkspaceUpdateEdge(WScreen *scr) +{ + if (!initVDesk && wPreferences.vedge_thickness) { + wWorkspaceManageEdge(scr); + } else if (initVDesk) { + if (wPreferences.vedge_thickness) { + wWorkspaceMapEdge(scr); + } else { + wWorkspaceUnmapEdge(scr); + } + } +} + + +void +wWorkspaceDestroyEdge(WScreen *scr) +{ + if (!initVDesk) { + int i; + + for (i=0; ivirtual_nr_edges; ++i) { + XDeleteContext(dpy, scr->virtual_edges[i], wVEdgeContext); + XDestroyWindow(dpy, scr->virtual_edges[i]); + } + + wfree(scr->virtual_edges); + scr->virtual_edges = NULL; + scr->virtual_nr_edges = 0; + + initVDesk = False; } } + void wWorkspaceRaiseEdge(WScreen *scr) { - puts("raise edge"); + static int toggle = 0; + int i; + if (wPreferences.vedge_thickness && initVDesk) { - XRaiseWindow(dpy, scr->virtual_edge_u); - XRaiseWindow(dpy, scr->virtual_edge_d); - XRaiseWindow(dpy, scr->virtual_edge_l); - XRaiseWindow(dpy, scr->virtual_edge_r); + if (toggle) { + for (i=0; ivirtual_nr_edges; ++i) { + XRaiseWindow(dpy, scr->virtual_edges[i]); + } + } else { + for (i=scr->virtual_nr_edges-1; i>=0; --i) { + XRaiseWindow(dpy, scr->virtual_edges[i]); + } + } + + toggle ^= 1; } } void wWorkspaceLowerEdge(WScreen *scr) { - puts("lower edge"); + int i; if (wPreferences.vedge_thickness && initVDesk) { - XLowerWindow(dpy, scr->virtual_edge_u); - XLowerWindow(dpy, scr->virtual_edge_d); - XLowerWindow(dpy, scr->virtual_edge_l); - XLowerWindow(dpy, scr->virtual_edge_r); + for (i=0; ivirtual_nr_edges; ++i) { + XLowerWindow(dpy, scr->virtual_edges[i]); + } } } + void -wWorkspaceResizeViewPort(WScreen *scr, int workspace, int width, int height) +wWorkspaceResizeViewPort(WScreen *scr, int workspace) { - scr->workspaces[workspace]->width = WMAX(width,scr->scr_width); - scr->workspaces[workspace]->height = WMAX(height,scr->scr_height); + int x, y; + wWorkspaceGetViewPosition(scr, scr->current_workspace, &x, &y); + wWorkspaceSetViewPort(scr, scr->current_workspace, x, y); } + void updateWorkspaceGeometry(WScreen *scr, int workspace, int *view_x, int *view_y) { int most_left, most_right, most_top, most_bottom; WWindow *wwin; + int heads = wXineramaHeads(scr); + typedef int strut_t[4]; + strut_t * strut = (strut_t*)wmalloc(heads*sizeof(strut_t)); + int head, i; + + for (head=0; headfocused_window; - most_right = scr->scr_width; - most_bottom = scr->scr_height; - most_left = 0; - most_top = 0; + most_right = 0; + most_bottom = 0; + most_left = scr->scr_width; + most_top = scr->scr_height; for(;wwin; wwin = wwin->prev) { if (wwin->frame->workspace == workspace) { - if (!wwin->flags.miniaturized - && !wwin->flags.hidden) { - if (wwin->frame_x < most_left) { /* record positions, should this be cached? */ - most_left = wwin->frame_x; - } - if ((int)wwin->frame_x + (int)wwin->frame->core->width > most_right) { - most_right = wwin->frame_x + wwin->frame->core->width; - } - if (wwin->frame_y < most_top) { - most_top = wwin->frame_y; - } - if (wwin->frame_y + wwin->frame->core->height > most_bottom) { - most_bottom = wwin->frame_y + wwin->frame->core->height; + if (!wwin->flags.miniaturized && !IS_VSTUCK(wwin) && + !wwin->flags.hidden) { + + head = wGetHeadForWindow(wwin); + + i = wwin->frame_x - strut[head][0]; + if (i < most_left) /* record positions, should this be cached? */ + most_left = i; + i = wwin->frame_x + wwin->frame->core->width + strut[head][1]; + if (HAS_BORDER(wwin)) + i+=2; + if (i > most_right) + most_right = i; + i = wwin->frame_y - strut[head][2]; + if (i < most_top) + most_top = i; + i = wwin->frame_y + wwin->frame->core->height + strut[head][3]; + if (HAS_BORDER(wwin)) + i+=2; + if (i > most_bottom) { + most_bottom = i; } } } } + if (most_left > 0) most_left = 0; + if (most_top > 0) most_top = 0; + scr->workspaces[workspace]->width = WMAX(most_right, scr->scr_width) - WMIN(most_left, 0); scr->workspaces[workspace]->height = WMAX(most_bottom, scr->scr_height) - WMIN(most_top, 0); @@ -741,6 +1176,7 @@ updateWorkspaceGeometry(WScreen *scr, int workspace, int *view_x, int *view_y) *view_y += -most_top - scr->workspaces[workspace]->view_y; scr->workspaces[workspace]->view_y = -most_top; + wfree(strut); } @@ -770,41 +1206,48 @@ wWorkspaceSetViewPort(WScreen *scr, int workspace, int view_x, int view_y) Bool adjust_flag = False; int diff_x, diff_y; static _delay_configure delay_configure = {NULL, 0}; + WWorkspace *wptr; WWindow *wwin; + wptr = scr->workspaces[workspace]; + /*printf("wWorkspaceSetViewPort %d %d\n", view_x, view_y);*/ updateWorkspaceGeometry(scr, workspace, &view_x, &view_y); - if (view_x + scr->scr_width > scr->workspaces[workspace]->width) { + if (view_x + scr->scr_width > wptr->width) { /* puts("right edge of vdesk"); */ - view_x = scr->workspaces[workspace]->width - scr->scr_width; + view_x = wptr->width - scr->scr_width; } if (view_x < 0) { /* puts("left edge of vdesk"); */ view_x = 0; } - if (view_y + scr->scr_height > scr->workspaces[workspace]->height) { + if (view_y + scr->scr_height > wptr->height) { /* puts("right edge of vdesk"); */ - view_y = scr->workspaces[workspace]->height - scr->scr_height; + view_y = wptr->height - scr->scr_height; } if (view_y < 0) { /* puts("left edge of vdesk"); */ view_y = 0; } - diff_x = scr->workspaces[workspace]->view_x - view_x; - diff_y = scr->workspaces[workspace]->view_y - view_y; + diff_x = wptr->view_x - view_x; + diff_y = wptr->view_y - view_y; if (!diff_x && !diff_y) return False; - scr->workspaces[workspace]->view_x = view_x; - scr->workspaces[workspace]->view_y = view_y; + wptr->view_x = view_x; + wptr->view_y = view_y; +#ifdef NETWM_HINTS + wNETWMUpdateDesktop(scr); +#endif for (wwin = scr->focused_window; wwin; wwin = wwin->prev) { - if (wwin->frame->workspace == workspace) { + if (wwin->frame->workspace == workspace && !IS_VSTUCK(wwin)) { wWindowMove(wwin, wwin->frame_x + diff_x, wwin->frame_y + diff_y); + adjust_flag = True; } } if (1) { /* if delay*/ @@ -818,15 +1261,14 @@ wWorkspaceSetViewPort(WScreen *scr, int workspace, int view_x, int view_y) void -wWorkspaceGetViewPosition(WScreen *scr, int workspace, int *view_x, int *view_y) +wWorkspaceGetViewPosition(WScreen *scr, int workspace, int *x, int *y) { - if (view_x) *view_x = scr->workspaces[workspace]->view_x; - if (view_y) *view_y = scr->workspaces[workspace]->view_y; + *x = scr->workspaces[workspace]->view_x; + *y = scr->workspaces[workspace]->view_y; } #endif - static void switchWSCommand(WMenu *menu, WMenuEntry *entry) { @@ -834,16 +1276,14 @@ switchWSCommand(WMenu *menu, WMenuEntry *entry) } - static void deleteWSCommand(WMenu *menu, WMenuEntry *entry) { wWorkspaceDelete(menu->frame->screen_ptr, - menu->frame->screen_ptr->workspace_count-1); + menu->frame->screen_ptr->workspace_count-1); } - static void newWSCommand(WMenu *menu, WMenuEntry *foo) { diff --git a/src/workspace.h b/src/workspace.h index 6f3cdcdd..7d0760de 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -41,12 +41,21 @@ void wWorkspaceChange(WScreen *scr, int workspace); void wWorkspaceForceChange(WScreen *scr, int workspace); #ifdef VIRTUAL_DESKTOP void wWorkspaceManageEdge(WScreen *scr); +void wWorkspaceUpdateEdge(WScreen *scr); +void wWorkspaceDestroyEdge(WScreen *scr); void wWorkspaceRaiseEdge(WScreen *scr); void wWorkspaceLowerEdge(WScreen *scr); -void wWorkspaceResizeViewPort(WScreen *scr, int workspace, int width, int height); +void wWorkspaceResizeViewPort(WScreen *scr, int workspace); +void wWorkspaceKeyboardMoveDesktop(WScreen *scr, WMPoint direction); Bool wWorkspaceSetViewPort(WScreen *scr, int workspace, int view_x, int view_y); Bool wWorkspaceAdjustViewPort(WScreen *scr, int workspace, int view_x, int view_y); void wWorkspaceGetViewPosition(WScreen *scr, int workspace, int *view_x, int *view_y); + +#define VEC_LEFT wmkpoint(-1,0) +#define VEC_RIGHT wmkpoint(1,0) +#define VEC_UP wmkpoint(0,-1) +#define VEC_DOWN wmkpoint(0,1) + #endif diff --git a/src/xdnd.c b/src/xdnd.c index 35085db7..b9a11dff 100644 --- a/src/xdnd.c +++ b/src/xdnd.c @@ -86,7 +86,7 @@ void wXDNDMakeAwareness(Window window) { } void wXDNDClearAwareness(Window window) { - long int xdnd_version = 3; + //long int xdnd_version = 3; XDeleteProperty (dpy, window, _XA_XdndAware); } diff --git a/src/xutil.c b/src/xutil.c index 71c9f981..964d602e 100644 --- a/src/xutil.c +++ b/src/xutil.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "wconfig.h" diff --git a/test/wtest.c b/test/wtest.c index 563dbe85..692a5341 100644 --- a/test/wtest.c +++ b/test/wtest.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include diff --git a/util/Makefile.am b/util/Makefile.am index d42a0a58..1346f994 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -3,9 +3,10 @@ AUTOMAKE_OPTIONS = no-dependencies pkgdatadir = $(datadir)/@PACKAGE@ -bin_PROGRAMS = wxcopy wxpaste wdwrite wdread getstyle setstyle seticons geticonset wmsetbg wmsetup wmagnify +bin_PROGRAMS = wxcopy wxpaste wdwrite wdread getstyle setstyle convertfonts \ + seticons geticonset wmsetbg wmsetup wmagnify -bin_SCRIPTS = wmaker.inst wm-oldmenu2new wsetfont wmchlocale wkdemenu.pl\ +bin_SCRIPTS = wmaker.inst wm-oldmenu2new wsetfont wmchlocale wkdemenu.pl \ wcopy wpaste EXTRA_DIST = wmaker.inst.in bughint wm-oldmenu2new wsetfont directjpeg.c \ @@ -31,6 +32,8 @@ setstyle_LDADD = \ $(top_builddir)/WINGs/libWUtil.a \ @XLFLAGS@ @XLIBS@ $(liblist) +convertfonts_LDADD = $(top_builddir)/WINGs/libWUtil.a $(liblist) + seticons_LDADD= $(top_builddir)/WINGs/libWUtil.a $(liblist) geticonset_LDADD= $(top_builddir)/WINGs/libWUtil.a $(liblist) diff --git a/util/convertfonts.c b/util/convertfonts.c new file mode 100644 index 00000000..2ed83a8a --- /dev/null +++ b/util/convertfonts.c @@ -0,0 +1,317 @@ +/* convertfonts.c - converts fonts in a style file to fontconfig format + * + * WindowMaker window manager + * + * Copyright (c) 2004 Dan Pascu + * + * 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. + */ + + +#define PROG_VERSION "convertfonts (Window Maker) 1.0" + +#include +#include +#include +#include +#include + +#include "../src/wconfig.h" + +#define DEFAULT_FONT "sans-serif:pixelsize=12" + +char *FontOptions[] = { + "IconTitleFont", + "ClipTitleFont", + "DisplayFont", + "LargeDisplayFont", + "MenuTextFont", + "MenuTitleFont", + "WindowTitleFont", + "SystemFont", + "BoldSystemFont", + NULL +}; + + +char *ProgName; + + +static int +countChar(char *str, char c) +{ + int count = 0; + + if (!str) + return 0; + + for (; *str!=0; str++) { + if (*str == c) { + count++; + } + } + + return count; +} + + +typedef struct str { + char *str; + int len; +} str; + +#define XLFD_TOKENS 14 + + +static str* +getXLFDTokens(char *xlfd) +{ + static str tokens[XLFD_TOKENS]; + int i, len, size; + char *ptr; + + if (!xlfd || *xlfd!='-' || countChar(xlfd, '-')0; i++) { + /* skip one '-' */ + ptr++; + len--; + if (len <= 0) + break; + size = strcspn(ptr, "-"); + tokens[i].str = ptr; + tokens[i].len = size; + ptr += size; + len -= size; + } + + return tokens; +} + + +static int +strToInt(str *token) +{ + int res=0, pos, c; + + if (token->len==0 || token->str[0]=='*') { + return -1; + } else { + for (res=0, pos=0; poslen; pos++) { + c = token->str[pos] - '0'; + if (c<0 || c>9) + break; + res = res*10 + c; + } + } + return res; +} + + +static char* +mapSlantToName(str *slant) +{ + if (slant->len==0 || slant->str[0]=='*') + return "roman"; + + switch(slant->str[0]) { + case 'i': + return "italic"; + case 'o': + return "oblique"; + case 'r': + default: + return "roman"; + } +} + + +char* +xlfdToFc(char *xlfd, char *useFamily, Bool keepXLFD) +{ + str *tokens, *family, *weight, *slant; + char *name, buf[512]; + int size, pixelsize; + + tokens = getXLFDTokens(xlfd); + if (!tokens) + return wstrdup(DEFAULT_FONT); + + family = &(tokens[1]); + weight = &(tokens[2]); + slant = &(tokens[3]); + + if (useFamily) { + name = wstrdup(useFamily); + } else { + if (family->len==0 || family->str[0]=='*') + return wstrdup(DEFAULT_FONT); + + sprintf(buf, "%.*s", family->len, family->str); + name = wstrdup(buf); + } + + pixelsize = strToInt(&tokens[6]); + size = strToInt(&tokens[7]); + + if (size<=0 && pixelsize<=0) { + name = wstrappend(name, ":pixelsize=12"); + } else if (pixelsize>0) { + /* if pixelsize is present size will be ignored so we skip it */ + sprintf(buf, ":pixelsize=%d", pixelsize); + name = wstrappend(name, buf); + } else { + sprintf(buf, "-%d", size/10); + name = wstrappend(name, buf); + } + + if (weight->len>0 && weight->str[0]!='*') { + sprintf(buf, ":weight=%.*s", weight->len, weight->str); + name = wstrappend(name, buf); + } + + if (slant->len>0 && slant->str[0]!='*') { + sprintf(buf, ":slant=%s", mapSlantToName(slant)); + name = wstrappend(name, buf); + } + + if (keepXLFD) { + name = wstrappend(name, ":xlfd="); + name = wstrappend(name, xlfd); + } + + return name; +} + + +/* return converted font (if conversion is needed) else the original font */ +static char* +convertFont(char *font, Bool keepXLFD) +{ + if (font[0]=='-') { + if (!strchr(font, ',')) { + return xlfdToFc(font, NULL, keepXLFD); + } else { + return xlfdToFc(font, "sans-serif", keepXLFD); + } + } else { + return font; + } +} + + +void +print_help() +{ + printf("\nUsage: %s \n\n", ProgName); + puts("Converts fonts in a style file into fontconfig format"); + puts(""); + puts(" --help display this help and exit"); + puts(" --version output version information and exit"); + puts(" --keep-xlfd preserve the original xlfd by appending a ':xlfd=' hint"); + puts(" to the font name. This property is not used by the fontconfig"); + puts(" matching engine to find the font, but it is useful as a hint"); + puts(" about what the original font was to allow hand tuning the"); + puts(" result or restoring the xlfd. The default is to not add it"); + puts(" as it results in long, unreadable and confusing names."); + puts(" --sets-too try to approximate fontsets by using their first complete xlfd."); + puts(" This only works for singlebyte languages. The default is to"); + puts(" replace the fontset with the default: 'sans-serif:pixelsize=12'"); + puts(" which should display properly for any language."); + puts(""); +} + +// replace --sets-too with something better +int +main(int argc, char **argv) +{ + WMPropList *style, *key, *val; + char *file = NULL, *oldfont, *newfont; + struct stat statbuf; + Bool keepXLFD = False; + int i; + + ProgName = argv[0]; + + if (argc<2) { + print_help(); + exit(0); + } + + for (i=1; i < argc; i++) { + if (strcmp("--version", argv[i])==0) { + puts(PROG_VERSION); + exit(0); + } else if (strcmp("--help", argv[i])==0) { + print_help(); + exit(0); + } else if (strcmp("--keep-xlfd", argv[i])==0) { + keepXLFD = True;; + } else if (argv[i][0]=='-') { + printf("%s: invalid argument '%s'\n", ProgName, argv[i]); + printf("Try '%s --help' for more information\n", ProgName); + exit(1); + } else { + file = argv[i]; + } + } + + WMPLSetCaseSensitive(False); + + if (stat(file, &statbuf) < 0) { + perror(file); + exit(1); + } + + style = WMReadPropListFromFile(file); + if (!style) { + perror(file); + printf("%s: could not load style file.\n", ProgName); + exit(1); + } + + if (!WMIsPLDictionary(style)) { + printf("%s: '%s' is not a well formatted style file\n", ProgName, file); + exit(1); + } + + for (i=0; FontOptions[i]!=NULL; i++) { + key = WMCreatePLString(FontOptions[i]); + val = WMGetFromPLDictionary(style, key); + if (val) { + oldfont = WMGetFromPLString(val); + newfont = convertFont(oldfont, keepXLFD); + if (oldfont != newfont) { + val = WMCreatePLString(newfont); + WMPutInPLDictionary(style, key, val); + WMReleasePropList(val); + wfree(newfont); + } + } + WMReleasePropList(key); + } + + WMWritePropListToFile(style, file, True); + + exit(0); +} + + diff --git a/util/geticonset.c b/util/geticonset.c index 4853d4ca..a1387f58 100644 --- a/util/geticonset.c +++ b/util/geticonset.c @@ -106,7 +106,7 @@ main(int argc, char **argv) exit(1); } - iconset = WMCreatePLDictionary(NULL, NULL, NULL); + iconset = WMCreatePLDictionary(NULL, NULL); keylist = WMGetPLDictionaryKeys(all_windows); icon_key = WMCreatePLString("Icon"); @@ -122,10 +122,7 @@ main(int argc, char **argv) if (window_attrs && WMIsPLDictionary(window_attrs)) { icon_value = WMGetFromPLDictionary(window_attrs, icon_key); if (icon_value) { - - icondic = WMCreatePLDictionary(icon_key, icon_value, - NULL); - + icondic = WMCreatePLDictionary(icon_key, icon_value, NULL); WMPutInPLDictionary(iconset, window_name, icondic); } } diff --git a/util/getstyle.c b/util/getstyle.c index e0c54625..9cfdd908 100644 --- a/util/getstyle.c +++ b/util/getstyle.c @@ -467,7 +467,7 @@ strToInt(str *token) int res=0, pos, c; if (token->len==0 || token->str[0]=='*') { - return -1; + return -1; } else { for (res=0, pos=0; poslen; pos++) { c = token->str[pos] - '0'; @@ -589,7 +589,7 @@ findCopyFile(char *dir, char *file) if (!fullPath) { char buffer[4000]; - sprintf(buffer, "coould not find file %s", file); + sprintf(buffer, "could not find file %s", file); abortar(buffer); } copyFile(dir, fullPath); @@ -763,7 +763,7 @@ main(int argc, char **argv) prop = val; } - style = WMCreatePLDictionary(NULL, NULL, NULL); + style = WMCreatePLDictionary(NULL, NULL); for (i=0; options[i]!=NULL; i++) { key = WMCreatePLString(options[i]); @@ -776,7 +776,7 @@ main(int argc, char **argv) oldfont = WMGetFromPLString(val); newfont = convertFont(oldfont); - /* font is a reference to old if conversion is not needed */ + /* newfont is a reference to old if conversion is not needed */ if (newfont != oldfont) { WMReleasePropList(val); val = WMCreatePLString(newfont); diff --git a/util/wmagnify.c b/util/wmagnify.c index 0ab49b79..9d6703d9 100644 --- a/util/wmagnify.c +++ b/util/wmagnify.c @@ -10,6 +10,7 @@ #include #include +#include #include /* diff --git a/util/wmsetbg.c b/util/wmsetbg.c index 31592cb0..ba7c56fa 100644 --- a/util/wmsetbg.c +++ b/util/wmsetbg.c @@ -495,7 +495,7 @@ parseTexture(RContext *rc, char *text) XColor color; Pixmap pixmap = None; RImage *image = NULL; - int w, h; + //int w, h; int iwidth, iheight; RColor rcolor; diff --git a/wmlib/app.c b/wmlib/app.c index 96e11a75..6a7f5769 100644 --- a/wmlib/app.c +++ b/wmlib/app.c @@ -21,6 +21,7 @@ #include #include +#include #include "WMaker.h" #include "app.h" diff --git a/wrlib/convert.c b/wrlib/convert.c index ba96643e..95689bba 100644 --- a/wrlib/convert.c +++ b/wrlib/convert.c @@ -678,7 +678,8 @@ image2StandardPseudoColor(RContext *ctx, RImage *image) int x1, ofs; #ifdef DEBUG - printf("pseudo color dithering with %d colors per channel\n", cpc); + printf("pseudo color dithering with %d colors per channel\n", + ctx->attribs->colors_per_channel); #endif err = (short*)malloc(3*(image->width+2)*sizeof(short)); nerr = (short*)malloc(3*(image->width+2)*sizeof(short)); diff --git a/wrlib/draw.c b/wrlib/draw.c index e8a7e3f6..777f37d3 100644 --- a/wrlib/draw.c +++ b/wrlib/draw.c @@ -279,7 +279,7 @@ clipLineInRectangle(int xmin, int ymin, int xmax, int ymax, } else if (ocode & RIG) { y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); x = xmax; - } else if (ocode & LEF) { + } else { //if (ocode & LEF) { y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1); x = xmin; } diff --git a/wrlib/x86_specific.c b/wrlib/x86_specific.c dissimilarity index 80% index 10bd5b6f..5f41cd06 100644 --- a/wrlib/x86_specific.c +++ b/wrlib/x86_specific.c @@ -1,696 +1,758 @@ -/* x86_convert.c - convert RImage to XImage with x86 optimizations - * - * Raster graphics library - * - * Copyright (c) 2000-2003 Alfredo K. Kojima - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#ifdef ASM_X86 - - -#ifdef ASM_X86_MMX - -int -x86_check_mmx() -{ - static int result = -1; - - if (result >= 0) - return result; - - result = 0; - - asm volatile - ("pushal \n" // please dont forget this in any asm - "pushfl \n" // check whether cpuid supported - "pop %%eax \n" - "movl %%eax, %%ebx \n" - "xorl $(1<<21), %%eax \n" - "pushl %%eax \n" - "popfl \n" - "pushfl \n" - "popl %%eax \n" - "xorl %%ebx, %%eax \n" - "andl $(1<<21), %%eax \n" - "jz .NotPentium \n" - "xorl %%eax, %%eax \n" // no eax effect because of the movl below - // except reseting flags. is it needed? - "movl $1, %%eax \n" - "cpuid \n" - "test $(1<<23), %%edx \n" - "jz .NotMMX \n" - - "popal \n" // popal needed because the address of - "movl $1, %0 \n" // variable %0 may be kept in a register - "jmp .noPop \n" - - ".NotMMX: \n" - ".NotPentium: \n" - "popal \n" - ".noPop: \n" - - : "=m" (result)); - - return result; -} - - -/* - * TODO: - * 32/8 24/8 32/16 24/16 32/24 24/24 - * PPlain YES YES - * MMX DONE - * - * - * - try to align stack (local variable space) into quadword boundary - */ - - - -void -x86_mmx_TrueColor_32_to_16(unsigned char *image, // 8 - unsigned short *ximage, // 12 - short *err, // 16 - short *nerr, // 20 - short *rtable, // 24 - short *gtable, // 28 - short *btable, // 32 - int dr, // 36 - int dg, // 40 - int db, // 44 - unsigned int roffs, // 48 - unsigned int goffs, // 52 - unsigned int boffs, // 56 - int width, // 60 - int height, // 64 - int line_offset) // 68 -{ - /* - int x; //-4 - long long rrggbbaa;// -16 - long long pixel; //-24 - short *tmp_err; //-32 - short *tmp_nerr; //-36 - */ - - asm volatile - ( - "subl $128, %esp \n" // alloc some more stack - - "pushal \n" - - // pack dr, dg and db into mm6 - "movl 36(%ebp), %eax \n" - "movl 40(%ebp), %ebx \n" - "movw %ax, -16(%ebp) \n" - - "movw %bx, -14(%ebp) \n" - "movl 44(%ebp), %eax \n" - "movw $0, -10(%ebp) \n" - "movw %ax, -12(%ebp) \n" - - "movq -16(%ebp), %mm6 \n" // dr dg db 0 - - // pack 4|4|4|4 into mm7, for shifting (/16) - "movl $0x00040004, -16(%ebp) \n" - "movl $0x00040004, -12(%ebp) \n" - "movq -16(%ebp), %mm7 \n" - - // store constant values for using with mmx when dithering - "movl $0x00070007, -16(%ebp) \n" - "movl $0x00070007, -12(%ebp) \n" - "movq -16(%ebp), %mm5 \n" - - "movl $0x00050005, -16(%ebp) \n" - "movl $0x00050005, -12(%ebp) \n" - "movq -16(%ebp), %mm4 \n" - - "movl $0x00030003, -16(%ebp) \n" - "movl $0x00030003, -12(%ebp) \n" - "movq -16(%ebp), %mm3 \n" - - // process 1 pixel / cycle, each component treated as 16bit - "movl 8(%ebp), %esi \n" // esi = image->data - -".LoopYa: \n" - "movl 60(%ebp), %eax \n" - "movl %eax, -4(%ebp) \n" // x = width - - "movl 64(%ebp), %eax \n" - "decl %eax \n" // y-- - "movl %eax, 64(%ebp) \n" - "js .Enda \n" // if y < 0, goto end - "andl $1, %eax \n" - "jz .LoopY_1a \n" // if (y&1) goto LoopY_1 - -".LoopY_0a: \n" - - "movl 16(%ebp), %ebx \n" // ebx = err - "movl %ebx, -36(%ebp) \n" // [-36] = err - "movl 20(%ebp), %eax \n" // - "movl %eax, -32(%ebp) \n" // [-32] = nerr - - "jmp .LoopXa \n" - -".LoopY_1a: \n" - - "movl 20(%ebp), %ebx \n" // ebx = nerr - "movl %ebx, -36(%ebp) \n" // [-36] = nerr - "movl 16(%ebp), %eax \n" // - "movl %eax, -32(%ebp) \n" // [-32] = eerr - - ".align 16 \n" -".LoopXa: \n" - - // calculate errors and pixel components - - // depend on ebx, esi, mm6 - "movq (%ebx), %mm1 \n" // mm1 = error[0..3] - "punpcklbw (%esi), %mm0 \n" // mm0 = image->data[0..3] - "psrlw $8, %mm0 \n" // fixup mm0 - "paddusb %mm1, %mm0 \n" // mm0 = mm0 + mm1 (sat. to 255) - "movq %mm0, -24(%ebp) \n" // save the pixel - - "movzwl -24(%ebp), %ecx \n" // ecx = pixel.red - "movl 24(%ebp), %edi \n" // edi = rtable - //agi - "leal (%edi, %ecx, 2), %eax \n" // eax = &rtable[pixel.red] - // agi - "movw (%eax), %dx \n" // dx = rtable[pixel.red] - "movw %dx, -16(%ebp) \n" // save rr - - "movzwl -22(%ebp), %ecx \n" // ecx = pixel.green - "movl 28(%ebp), %edi \n" // edi = gtable - //agi - "leal (%edi, %ecx, 2), %eax \n" // eax = >able[pixel.green] - //agi - "movw (%eax), %dx \n" // dx = gtable[pixel.green] - "movw %dx, -14(%ebp) \n" // save gg - - "movzwl -20(%ebp), %ecx \n" // ecx = pixel.blue - "movl 32(%ebp), %edi \n" // ebx = btable - //agi - "leal (%edi, %ecx, 2), %eax \n" // eax = &btable[pixel.blue] - //agi - "movw (%eax), %dx \n" // dx = btable[pixel.blue] - "movw %dx, -12(%ebp) \n" // save bb - - "movw $0, -10(%ebp) \n" // save dummy aa - - "movq -16(%ebp), %mm1 \n" // load mm1 with rrggbbaa - "pmullw %mm6, %mm1 \n" // mm1 = rr*dr|... - "psubsw %mm1, %mm0 \n" // error = pixel - mm1 - - - // distribute the error - - // depend on mm0, mm7, mm3, mm4, mm5 - - "movl -36(%ebp), %ebx \n" - - "movq %mm0, %mm1 \n" - "pmullw %mm5, %mm1 \n" // mm1 = mm1*7 - "psrlw %mm7, %mm1 \n" // mm1 = mm1/16 - "paddw 8(%ebx), %mm1 \n" - "movq %mm1, 8(%ebx) \n" // err[x+1,y] = rer*7/16 - - - "movl -32(%ebp), %ebx \n" - - "movq %mm0, %mm1 \n" - "pmullw %mm4, %mm1 \n" // mm1 = mm1*5 - "psrlw %mm7, %mm1 \n" // mm1 = mm1/16 - "paddw -8(%ebx), %mm1 \n" - "movq %mm1, -8(%ebx) \n" // err[x-1,y+1] += rer*3/16 - - "movq %mm0, %mm1 \n" - "pmullw %mm3, %mm1 \n" // mm1 = mm1*3 - "psrlw %mm7, %mm1 \n" // mm1 = mm1/16 - "paddw 8(%ebx), %mm1 \n" - "movq %mm1, (%ebx) \n" // err[x,y+1] += rer*5/16 - - "psrlw %mm7, %mm0 \n" // mm0 = mm0/16 - "movq %mm0, 8(%ebx) \n" // err[x+1,y+1] = rer/16 - - - // calculate final pixel value and store - "movl 48(%ebp), %ecx \n" - "movw -16(%ebp), %ax \n" - "shlw %cl, %ax \n" //NP* ax = r<data += 4 - - - "decl -4(%ebp) \n" // x-- - "jnz .LoopXa \n" // if x>0, goto .LoopX - - - // depend on edx - "addl 68(%ebp), %edx \n" // add extra offset to ximage - "movl %edx, 12(%ebp) \n" - - - "jmp .LoopYa \n" - -".Enda: \n" // THE END - - "emms \n" - - "popal \n" - ); -} - - - - - - -void -x86_mmx_TrueColor_24_to_16(unsigned char *image, // 8 - unsigned short *ximage, // 12 - short *err, // 16 - short *nerr, // 20 - short *rtable, // 24 - short *gtable, // 28 - short *btable, // 32 - int dr, // 36 - int dg, // 40 - int db, // 44 - unsigned int roffs, // 48 - unsigned int goffs, // 52 - unsigned int boffs, // 56 - int width, // 60 - int height, // 64 - int line_offset) // 68 -{ - /* - int x; //-4 - long long rrggbbaa;// -16 - long long pixel; //-24 - short *tmp_err; //-32 - short *tmp_nerr; //-36 - * - int w1; // -64 - int w2; // -68 - */ - - asm volatile - ( - "subl $128, %esp \n" // alloc some more stack - - "pushal \n" - - "movl 60(%ebp), %eax \n" // eax = width - "movl %eax, %ebx \n" - "shrl $2, %eax \n" - "movl %eax, -64(%ebp) \n" // w1 = width / 4 - "andl $3, %ebx \n" - "movl %ebx, -68(%ebp) \n" // w2 = width % 4 - - -".LoopYc: \n" - "movl 60(%ebp), %eax \n" - "movl %eax, -4(%ebp) \n" // x = width - - "decl 64(%ebp) \n" // height-- - "js .Endc \n" // if height < 0 then end - - "movl 64(%ebp), %eax \n" - "decl %eax \n" // y-- - "movl %eax, 64(%ebp) \n" - "js .Endc \n" // if y < 0, goto end - "andl $1, %eax \n" - "jz .LoopY_1c \n" // if (y&1) goto LoopY_1 - -".LoopY_0c: \n" - - "movl 16(%ebp), %ebx \n" // ebx = err - "movl %ebx, -36(%ebp) \n" // [-36] = err - "movl 20(%ebp), %eax \n" // - "movl %eax, -32(%ebp) \n" // [-32] = nerr - - "jmp .LoopX_1c \n" - -".LoopY_1c: \n" - - "movl 20(%ebp), %ebx \n" // ebx = nerr - "movl %ebx, -36(%ebp) \n" // [-36] = nerr - "movl 16(%ebp), %eax \n" // - "movl %eax, -32(%ebp) \n" // [-32] = eerr - - ".align 16 \n" - - "movl %eax, -4(%ebp) \n" // x = w1 -".LoopX_1c: \n" - "decl -4(%ebp) \n" // x-- - "js .Xend1_c \n" // if x < 0 then end - - // do conversion of 4 pixels - "movq 16(%ebp), %mm0 \n" // mm0 = err - - - - - "jmp .LoopX_1c \n" -".Xend1_c: \n" - - "movl -68(%ebp), %eax \n" - "movl %eax, -4(%ebp) \n" // x = w2 -".LoopX_2c: \n" - "decl -4(%ebp) \n" // x-- - "js .Xend2_c \n" // - // do conversion - "jmp .LoopX_2c \n" -".Xend2_c: \n" - - "movl -64(%ebp), %eax \n" - "jmp .LoopYc \n" - -".Endc: \n" // THE END - - "emms \n" - - "popal \n" - ); -} - - - -#endif /* ASM_X86_MMX */ - - - -void -x86_PseudoColor_32_to_8(unsigned char *image, // 8 - unsigned char *ximage, // 12 - char *err, // 16 - char *nerr, // 20 - short *ctable, // 24 - int dr, // 28 - int dg, // 32 - int db, // 36 - unsigned long *pixels, // 40 - int cpc, // 44 - int width, // 48 - int height, // 52 - int bytesPerPixel, // 56 - int line_offset) // 60 -{ - /* - * int x; -4 - * int cpcpc; -8 - * - * int rr; -12 - * int gg; -16 - * int bb; -20 - * - * char ndr; -21 - * char ndg; -22 - * char ndb; -23 - * - * char *err; -32 - * char *nerr; -36 - * - */ - asm volatile - ( - "subl $128, %esp \n" // alloc some stack space - "pushal \n" - - "movl 44(%ebp), %eax \n" - "mulb 44(%ebp) \n" - "movl %eax, -8(%ebp) \n" // cpcpc = cpc*cpc - - // eax will always be <= 0xffff - - // process 1 pixel / cycle, each component treated as 16bit - "movl 8(%ebp), %esi \n" // esi = image->data - -".LoopYb: \n" - "movl 48(%ebp), %ecx \n" - "movl %ecx, -4(%ebp) \n" // x = width - - "movl 52(%ebp), %ecx \n" - "decl %ecx \n" // y-- - "movl %ecx, 52(%ebp) \n" - "js .Endb \n" // if y < 0, goto end - "andl $1, %ecx \n" - "jz .LoopY_1b \n" // if (y&1) goto LoopY_1 - -".LoopY_0b: \n" - - "movl 16(%ebp), %ebx \n" // ebx = err -//useless "movl %ebx, -36(%ebp) \n" // [-36] = err - "movl 20(%ebp), %ecx \n" // - "movl %ecx, -32(%ebp) \n" // [-32] = nerr - - "movl $0, (%ecx) \n" // init error of nerr[0] to 0 - - "jmp .LoopXb \n" - -".LoopY_1b: \n" - - "movl 20(%ebp), %ebx \n" // ebx = nerr -//useless "movl %ebx, -36(%ebp) \n" // [-36] = nerr - "movl 16(%ebp), %ecx \n" // - "movl %ecx, -32(%ebp) \n" // [-32] = err - - "movl $0, (%ecx) \n" // init error of nerr[0] to 0 - - - ".align 16 \n" -".LoopXb: \n" - - - "movl 24(%ebp), %edi \n" // edi = ctable - "xorl %edx, %edx \n" // zero the upper word on edx - - // RED - - // depends on ebx==err, esi==image->data, edi - "movzbw (%esi), %dx \n" // dx = image->data[0] - "movsbw (%ebx), %ax \n" // ax = error[0] - "addw %ax, %dx \n" // pixel.red = data[0] + error[0] - - "testb %dh, %dh \n" // test if pixel.red < 0 or > 255 - "jz .OKRb \n" // 0 <= pixel.red <= 255 - "js .NEGRb \n" // pixel.red < 0 - "movw $0xff, %dx \n" // pixel.red > 255 - "jmp .OKRb \n" -".NEGRb: \n" - "xorw %dx, %dx \n" -".OKRb: \n" - //partial reg - "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.red] - //agi - "movl (%ecx), %eax \n" // ax = ctable[pixel.red] - "movw %ax, -12(%ebp) \n" // save rr - - "mulb 28(%ebp) \n" // ax = rr*dr - "subw %ax, %dx \n" // rer = dx = dx - rr*dr - - "movswl %dx, %eax \n" // save rer - - // distribute error - "leal (, %eax, 8), %ecx \n" - "subw %dx, %cx \n" // cx = rer * 7 - "sarw $4, %cx \n" // cx = rer * 7 / 16 - "addb %cl, 4(%ebx) \n" // err[x+1] += rer * 7 / 16 - - "movl -32(%ebp), %ecx \n" // ecx = nerr - - "leaw (%eax, %eax, 4), %dx \n" // dx = rer * 5 - "sarw $4, %dx \n" // dx = rer * 5 / 16 - "addb %dl, (%ecx) \n" // nerr[x] += rer * 5 / 16 - - "leaw (%eax, %eax, 2), %dx \n" // dx = rer * 3 - "sarw $4, %dx \n" // dx = rer * 3 / 16 - "addb %dl, -4(%ecx) \n" // nerr[x-1] += rer * 3 / 16 - - "sarw $4, %ax \n" // ax = rer / 16 - "movb %al, 4(%ecx) \n" // nerr[x+1] = rer / 16 - - - // GREEN - - // depends on ebx, esi, edi - "movzbw 1(%esi), %dx \n" // dx = image->data[1] - "movsbw 1(%ebx), %ax \n" // ax = error[1] - "addw %ax, %dx \n" // pixel.grn = data[1] + error[1] - - "testb %dh, %dh \n" // test if pixel.grn < 0 or > 255 - "jz .OKGb \n" // 0 <= pixel.grn <= 255 - "js .NEGGb \n" // pixel.grn < 0 - "movw $0xff, %dx \n" // pixel.grn > 255 - "jmp .OKGb \n" -".NEGGb: \n" - "xorw %dx, %dx \n" -".OKGb: \n" - // partial reg - "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.grn] - //agi - "movw (%ecx), %ax \n" // ax = ctable[pixel.grn] - "movw %ax, -16(%ebp) \n" // save gg - - "mulb 28(%ebp) \n" // ax = gg*dg - "subw %ax, %dx \n" // ger = dx = dx - gg*dg - - "movswl %dx, %eax \n" // save ger - - // distribute error - - "leal (, %eax, 8), %ecx \n" - "subw %dx, %cx \n" // cx = ger * 7 - "sarw $4, %cx \n" // cx = ger * 7 / 16 - "addb %cl, 5(%ebx) \n" // err[x+1] += ger * 7 / 16 - - "movl -32(%ebp), %ecx \n" // ecx = nerr - - "leaw (%eax, %eax, 4), %dx \n" // dx = ger * 5 - "sarw $4, %dx \n" // dx = ger * 5 / 16 - "addb %dl, 1(%ecx) \n" // nerr[x] += ger * 5 / 16 - - "leaw (%eax, %eax, 2), %dx \n" // dx = ger * 3 - "sarw $4, %dx \n" // dx = ger * 3 / 16 - "addb %dl, -3(%ecx) \n" // nerr[x-1] += ger * 3 / 16 - - "sarw $4, %ax \n" // ax = ger / 16 - "movb %al, 5(%ecx) \n" // nerr[x+1] = ger / 16 - - - // BLUE - - // depends on ebx, esi - "movzbw 2(%esi), %dx \n" // dx = image->data[2] - "movsbw 2(%ebx), %ax \n" // ax = error[2] - "addw %ax, %dx \n" // pixel.grn = data[2] + error[2] - - "testb %dh, %dh \n" // test if pixel.blu < 0 or > 255 - "jz .OKBb \n" // 0 <= pixel.blu <= 255 - "js .NEGBb \n" // pixel.blu < 0 - "movw $0xff, %dx \n" // pixel.blu > 255 - "jmp .OKBb \n" -".NEGBb: \n" - "xorw %dx, %dx \n" -".OKBb: \n" - //partial reg - "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.blu] - //agi - "movw (%ecx), %ax \n" // ax = ctable[pixel.blu] - "movw %ax, -20(%ebp) \n" // save bb - - "mulb 28(%ebp) \n" // ax = bb*db - "subw %ax, %dx \n" // ber = dx = dx - bb*db - "movswl %dx, %eax \n" // save ber - - // distribute error - "leal (, %eax, 8), %ecx \n" - "subw %dx, %cx \n" // cx = ber * 7 - "sarw $4, %cx \n" // cx = ber * 7 / 16 - "addb %cl, 6(%ebx) \n" // err[x+1] += ber * 7 / 16 - - "movl -32(%ebp), %ecx \n" // ecx = nerr - - "leaw (%eax, %eax, 4), %dx \n" // dx = ber * 5 - "sarw $4, %dx \n" // dx = ber * 5 / 16 - "addb %dl, 2(%ecx) \n" // nerr[x] += ber * 5 / 16 - - "leaw (%eax, %eax, 2), %dx \n" // dx = ber * 3 - "sarw $4, %dx \n" // dx = ber * 3 / 16 - "addb %dl, -4(%ecx) \n" // nerr[x-1] += ber * 3 / 16 - - "sarw $4, %ax \n" // ax = ber / 16 - "movb %al, 6(%ecx) \n" // nerr[x+1] = ber / 16 - - "andl $0xffff, %eax \n" - // depends on eax & 0xffff0000 == 0 - // calculate the index of the value of the pixel - "movw -12(%ebp), %ax \n" // ax = rr - "mulb -8(%ebp) \n" // ax = cpcpc*rr - "movw %ax, %cx \n" - "movw -16(%ebp), %ax \n" // ax = gg - "mulb 44(%ebp) \n" // ax = cpc*gg - "addw %cx, %ax \n" // ax = cpc*gg + cpcpc*rr - "addw -20(%ebp), %ax \n" // ax = cpcpc*rr + cpc*gg + bb - - "movl 40(%ebp), %ecx \n" - //agi - "leal (%ecx, %eax, 4), %edx \n" - //agi - "movb (%edx), %cl \n" // cl = pixels[ax] - - // store the pixel - "movl 12(%ebp), %eax \n" - "movb %cl, (%eax) \n" // *ximage = cl - "incl 12(%ebp) \n" // ximage++ - - // prepare for next iteration on X - - "addl $4, -32(%ebp) \n" // nerr += 4 - "addl $4, %ebx \n" // err += 4 - - "addl 56(%ebp), %esi \n" // image->data += bpp - - "decl -4(%ebp) \n" // x-- - "jnz .LoopXb \n" // if x>0, goto .LoopX - - - "movl 60(%ebp), %eax \n" - "addl %eax, 12(%ebp) \n" // add extra offset to ximage - - "jmp .LoopYb \n" - -".Endb: \n" - - "emms \n" - "popal \n" - ); - - -} - -#endif /* ASM_X86 */ +/* x86_convert.c - convert RImage to XImage with x86 optimizations + * + * Raster graphics library + * + * Copyright (c) 2000-2003 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#ifdef ASM_X86 + + +#ifdef ASM_X86_MMX + +int +x86_check_mmx() +{ + static int result = -1; + + if (result >= 0) + return result; + + result = 0; + + asm volatile + ("pushal \n\t" // please dont forget this in any asm + "pushfl \n\t" // check whether cpuid supported + "pop %%eax \n\t" + "movl %%eax, %%ebx \n\t" + "xorl $(1<<21), %%eax \n\t" + "pushl %%eax \n\t" + "popfl \n\t" + "pushfl \n\t" + "popl %%eax \n\t" + "xorl %%ebx, %%eax \n\t" + "andl $(1<<21), %%eax \n\t" + "jz .NotPentium \n\t" + "xorl %%eax, %%eax \n\t" // no eax effect because of the movl below + // except reseting flags. is it needed? + "movl $1, %%eax \n\t" + "cpuid \n\t" + "test $(1<<23), %%edx \n\t" + "jz .NotMMX \n\t" + + "popal \n\t" // popal needed because the address of + "movl $1, %0 \n\t" // variable %0 may be kept in a register + "jmp .noPop \n" + +".NotMMX: \n" +".NotPentium: \n\t" + "popal \n" +".noPop: \n\t" + + : "=m" (result)); + + return result; +} + + +/* + * TODO: + * 32/8 24/8 32/16 24/16 32/24 24/24 + * PPlain YES YES + * MMX DONE + * + * + * - try to align stack (local variable space) into quadword boundary + */ +void +x86_mmx_TrueColor_32_to_16(unsigned char *image, + unsigned short *ximage, + short *err, + short *nerr, + short *rtable, + short *gtable, + short *btable, + int dr, + int dg, + int db, + unsigned int roffs, + unsigned int goffs, + unsigned int boffs, + int width, + int height, + int line_offset) +{ + long long rrggbbaa; + long long pixel; + short *tmp_err; + short *tmp_nerr; + int x; + + asm volatile + ( + "pushal \n\t" + + // pack dr, dg and db into mm6 + "movl %7, %%eax \n\t" + "movl %8, %%ebx \n\t" + "movl %9, %%ecx \n\t" + "movw %%ax, %16 \n\t" + "movw %%bx, %17 \n\t" + "movw %%cx, %18 \n\t" + "movw $0, %19 \n\t" + + "movq %16, %%mm6 \n\t" // dr dg db 0 + + // pack 4|4|4|4 into mm7, for shifting (/16) + "movl $0x00040004, %16 \n\t" + "movl $0x00040004, %18 \n\t" + "movq %16, %%mm7 \n\t" + + // store constant values for using with mmx when dithering + "movl $0x00070007, %16 \n\t" + "movl $0x00070007, %18 \n\t" + "movq %16, %%mm5 \n\t" + + "movl $0x00050005, %16 \n\t" + "movl $0x00050005, %18 \n\t" + "movq %16, %%mm4 \n\t" + + "movl $0x00030003, %16 \n\t" + "movl $0x00030003, %18 \n\t" + "movq %16, %%mm3 \n\t" + + // process 1 pixel / cycle, each component treated as 16bit + "movl %0, %%esi \n" // esi = image->data + +".LoopYa: \n\t" + "movl %13, %%eax \n\t" + "movl %%eax, %26 \n\t" // x = width + + "movl %14, %%eax \n\t" + "decl %%eax \n\t" // y-- + "movl %%eax, %14 \n\t" + "js .Enda \n\t" // if y < 0, goto end + "andl $1, %%eax \n\t" + "jz .LoopY_1a \n" // if (y&1) goto LoopY_1 + +".LoopY_0a: \n\t" + + "movl %2, %%ebx \n\t" // ebx = err + "movl %%ebx, %25 \n\t" // [-36] = err + "movl %3, %%eax \n\t" // + "movl %%eax, %24 \n\t" // [-32] = nerr + + "jmp .LoopXa \n" + +".LoopY_1a: \n\t" + + "movl %3, %%ebx \n\t" // ebx = nerr + "movl %%ebx, %25 \n\t" // [-36] = nerr + "movl %2, %%eax \n\t" // + "movl %%eax, %24 \n\t" // [-32] = eerr + + ".align 16 \n" +".LoopXa: \n\t" + + // calculate errors and pixel components + + // depend on ebx, esi, mm6 + "movq (%%ebx), %%mm1 \n\t" // mm1 = error[0..3] + "punpcklbw (%%esi), %%mm0 \n\t" // mm0 = image->data[0..3] + "psrlw $8, %%mm0 \n\t" // fixup mm0 + "paddusb %%mm1, %%mm0 \n\t" // mm0 = mm0 + mm1 (sat. to 255) + "movq %%mm0, %20 \n\t" // save the pixel + + "movzwl %20, %%ecx \n\t" // ecx = pixel.red + "movl %4, %%edi \n\t" // edi = rtable + //agi + "leal (%%edi, %%ecx, 2), %%eax \n\t" // eax = &rtable[pixel.red] + // agi + "movw (%%eax), %%dx \n\t" // dx = rtable[pixel.red] + "movw %%dx, %16 \n\t" // save rr + + "movzwl %21, %%ecx \n\t" // ecx = pixel.green + "movl %5, %%edi \n\t" // edi = gtable + //agi + "leal (%%edi, %%ecx, 2), %%eax \n\t" // eax = >able[pixel.green] + //agi + "movw (%%eax), %%dx \n\t" // dx = gtable[pixel.green] + "movw %%dx, %17 \n\t" // save gg + + "movzwl %22, %%ecx \n\t" // ecx = pixel.blue + "movl %6, %%edi \n\t" // ebx = btable + //agi + "leal (%%edi, %%ecx, 2), %%eax \n\t" // eax = &btable[pixel.blue] + //agi + "movw (%%eax), %%dx \n\t" // dx = btable[pixel.blue] + "movw %%dx, %18 \n\t" // save bb + + "movw $0, %19 \n\t" // save dummy aa + + "movq %16, %%mm1 \n\t" // load mm1 with rrggbbaa + "pmullw %%mm6, %%mm1 \n\t" // mm1 = rr*dr|... + "psubsw %%mm1, %%mm0 \n\t" // error = pixel - mm1 + + + // distribute the error + + // depend on mm0, mm7, mm3, mm4, mm5 + + "movl %25, %%ebx \n\t" + + "movq %%mm0, %%mm1 \n\t" + "pmullw %%mm5, %%mm1 \n\t" // mm1 = mm1*7 + "psrlw %%mm7, %%mm1 \n\t" // mm1 = mm1/16 + "paddw 8(%%ebx), %%mm1 \n\t" + "movq %%mm1, 8(%%ebx) \n\t" // err[x+1,y] = rer*7/16 + + + "movl %24, %%ebx \n\t" + + "movq %%mm0, %%mm1 \n\t" + "pmullw %%mm4, %%mm1 \n\t" // mm1 = mm1*5 + "psrlw %%mm7, %%mm1 \n\t" // mm1 = mm1/16 + "paddw -8(%%ebx), %%mm1 \n\t" + "movq %%mm1, -8(%%ebx) \n\t" // err[x-1,y+1] += rer*3/16 + + "movq %%mm0, %%mm1 \n\t" + "pmullw %%mm3, %%mm1 \n\t" // mm1 = mm1*3 + "psrlw %%mm7, %%mm1 \n\t" // mm1 = mm1/16 + "paddw 8(%%ebx), %%mm1 \n\t" + "movq %%mm1, (%%ebx) \n\t" // err[x,y+1] += rer*5/16 + + "psrlw %%mm7, %%mm0 \n\t" // mm0 = mm0/16 + "movq %%mm0, 8(%%ebx) \n\t" // err[x+1,y+1] = rer/16 + + + // calculate final pixel value and store + "movl %10, %%ecx \n\t" + "movw %16, %%ax \n\t" + "shlw %%cl, %%ax \n\t" //NP* ax = r<data += 4 + + + "decl %26 \n\t" // x-- + "jnz .LoopXa \n\t" // if x>0, goto .LoopX + + + // depend on edx + "addl %15, %%edx \n\t" // add extra offset to ximage + "movl %%edx, %1 \n\t" + + + "jmp .LoopYa \n" + +".Enda: \n\t" // THE END + "emms \n\t" + "popal \n\t" + : + : + "m" (image), // %0 + "m" (ximage), // %1 + "m" (err), // %2 + "m" (nerr), // %3 + "m" (rtable), // %4 + "m" (gtable), // %5 + "m" (btable), // %6 + "m" (dr), // %7 + "m" (dg), // %8 + "m" (db), // %9 + "m" (roffs), // %10 + "m" (goffs), // %11 + "m" (boffs), // %12 + "m" (width), // %13 + "m" (height), // %14 + "m" (line_offset), // %15 + "m" (rrggbbaa), // %16 (access to rr) + "m" ((*((short*)(&rrggbbaa)+1))), // %17 (access to gg) + "m" ((*((short*)(&rrggbbaa)+2))), // %18 (access to bb) + "m" ((*((short*)(&rrggbbaa)+3))), // %19 (access to aa) + "m" (pixel), // %20 (access to pixel.r) + "m" ((*((short*)(&pixel)+1))), // %21 (access to pixel.g) + "m" ((*((short*)(&pixel)+2))), // %22 (access to pixel.b) + "m" ((*((short*)(&pixel)+3))), // %23 (access to pixel.a) + "m" (tmp_err), // %24 + "m" (tmp_nerr), // %25 + "m" (x) // %26 + ); +} + + +void +x86_mmx_TrueColor_24_to_16(unsigned char *image, + unsigned short *ximage, + short *err, + short *nerr, + short *rtable, + short *gtable, + short *btable, + int dr, + int dg, + int db, + unsigned int roffs, + unsigned int goffs, + unsigned int boffs, + int width, + int height, + int line_offset) +{ + long long rrggbbaa; + long long pixel; + + short *tmp_err; + short *tmp_nerr; + + int x; + int w1; + int w2; + + asm volatile + ( + "pushal \n\t" + + "movl %13, %%eax \n\t" // eax = width + "movl %%eax, %%ebx \n\t" + "shrl $2, %%eax \n\t" + "movl %%eax, %27 \n\t" // w1 = width / 4 + "andl $3, %%ebx \n\t" + "movl %%ebx, %28 \n" // w2 = width %% 4 + + +".LoopYc: \n\t" + "movl %13, %%eax \n\t" + "movl %%eax, %26 \n\t" // x = width + + "decl %14 \n\t" // height-- + "js .Endc \n\t" // if height < 0 then end + + "movl %14, %%eax \n\t" + "decl %%eax \n\t" // y-- + "movl %%eax, %14 \n\t" + "js .Endc \n\t" // if y < 0, goto end + "andl $1, %%eax \n\t" + "jz .LoopY_1c \n" // if (y&1) goto LoopY_1 + +".LoopY_0c: \n\t" + + "movl %2, %%ebx \n\t" // ebx = err + "movl %%ebx, %25 \n\t" // [-36] = err + "movl %3, %%eax \n\t" // + "movl %%eax, %24 \n\t" // [-32] = nerr + + "jmp .LoopX_1c \n" + +".LoopY_1c: \n\t" + + "movl %3, %%ebx \n\t" // ebx = nerr + "movl %%ebx, %25 \n\t" // [-36] = nerr + "movl %2, %%eax \n\t" // + "movl %%eax, %24 \n\t" // [-32] = eerr + + ".align 16 \n\t" + + "movl %%eax, %26 \n" // x = w1 +".LoopX_1c: \n\t" + "decl %26 \n\t" // x-- + "js .Xend1_c \n\t" // if x < 0 then end + + // do conversion of 4 pixels + "movq %2, %%mm0 \n\t" // mm0 = err + + + + + "jmp .LoopX_1c \n" +".Xend1_c: \n\t" + + "movl %28, %%eax \n\t" + "movl %%eax, %26 \n" // x = w2 +".LoopX_2c: \n\t" + "decl %26 \n\t" // x-- + "js .Xend2_c \n\t" // + // do conversion + "jmp .LoopX_2c \n" +".Xend2_c: \n\t" + + "movl %27, %%eax \n\t" + "jmp .LoopYc \n" + +".Endc: \n\t" // THE END + "emms \n\t" + "popal \n\t" + : + : + "m" (image), // %0 + "m" (ximage), // %1 + "m" (err), // %2 + "m" (nerr), // %3 + "m" (rtable), // %4 + "m" (gtable), // %5 + "m" (btable), // %6 + "m" (dr), // %7 + "m" (dg), // %8 + "m" (db), // %9 + "m" (roffs), // %10 + "m" (goffs), // %11 + "m" (boffs), // %12 + "m" (width), // %13 + "m" (height), // %14 + "m" (line_offset), // %15 + "m" (rrggbbaa), // %16 (access to rr) + "m" ((*((short*)(&rrggbbaa)+1))), // %17 (access to gg) + "m" ((*((short*)(&rrggbbaa)+2))), // %18 (access to bb) + "m" ((*((short*)(&rrggbbaa)+3))), // %19 (access to aa) + "m" (pixel), // %20 (access to pixel.r) + "m" ((*((short*)(&pixel)+1))), // %21 (access to pixel.g) + "m" ((*((short*)(&pixel)+2))), // %22 (access to pixel.b) + "m" ((*((short*)(&pixel)+3))), // %23 (access to pixel.a) + "m" (tmp_err), // %24 + "m" (tmp_nerr), // %25 + "m" (x), // %26 + "m" (w1), // %27 + "m" (w2) // %28 + ); +} + + + +#endif /* ASM_X86_MMX */ + + + +void +x86_PseudoColor_32_to_8(unsigned char *image, + unsigned char *ximage, + char *err, + char *nerr, + short *ctable, + int dr, + int dg, + int db, + unsigned long *pixels, + int cpc, + int width, + int height, + int bytesPerPixel, + int line_offset) +{ + int x; + int cpcpc; + + int rr; + int gg; + int bb; + + char *tmp_err; + char *tmp_nerr; + + char ndr; // aparently not used + char ndg; // aparently not used + char ndb; // aparently not used + + asm volatile + ( + "pushal \n\t" + + "movl %9, %%eax \n\t" + "mulb %9 \n\t" + "movl %%eax, %15 \n\t" // cpcpc = cpc*cpc + + // eax will always be <= 0xffff + + // process 1 pixel / cycle, each component treated as 16bit + "movl %0, %%esi \n" // esi = image->data + +".LoopYb: \n\t" + "movl %10, %%ecx \n\t" + "movl %%ecx, %14 \n\t" // x = width + + "movl %11, %%ecx \n\t" + "decl %%ecx \n\t" // y-- + "movl %%ecx, %11 \n\t" + "js .Endb \n\t" // if y < 0, goto end + "andl $1, %%ecx \n\t" + "jz .LoopY_1b \n" // if (y&1) goto LoopY_1 + +".LoopY_0b: \n\t" + + "movl %2, %%ebx \n\t" // ebx = err +//useless "movl %%ebx, %20 \n\t" // [-36] = err + "movl %3, %%ecx \n\t" // + "movl %%ecx, %19 \n\t" // [-32] = nerr + + "movl $0, (%%ecx) \n\t" // init error of nerr[0] to 0 + + "jmp .LoopXb \n" + +".LoopY_1b: \n\t" + + "movl %3, %%ebx \n\t" // ebx = nerr +//useless "movl %%ebx, %20 \n\t" // [-36] = nerr + "movl %2, %%ecx \n\t" // + "movl %%ecx, %19 \n\t" // [-32] = err + + "movl $0, (%%ecx) \n\t" // init error of nerr[0] to 0 + + + ".align 16 \n" +".LoopXb: \n\t" + + + "movl %4, %%edi \n\t" // edi = ctable + "xorl %%edx, %%edx \n\t" // zero the upper word on edx + + // RED + + // depends on ebx==err, esi==image->data, edi + "movzbw (%%esi), %%dx \n\t" // dx = image->data[0] + "movsbw (%%ebx), %%ax \n\t" // ax = error[0] + "addw %%ax, %%dx \n\t" // pixel.red = data[0] + error[0] + + "testb %%dh, %%dh \n\t" // test if pixel.red < 0 or > 255 + "jz .OKRb \n\t" // 0 <= pixel.red <= 255 + "js .NEGRb \n\t" // pixel.red < 0 + "movw $0xff, %%dx \n\t" // pixel.red > 255 + "jmp .OKRb \n" +".NEGRb: \n\t" + "xorw %%dx, %%dx \n" +".OKRb: \n\t" + //partial reg + "leal (%%edi, %%edx, 2), %%ecx \n\t" // ecx = &ctable[pixel.red] + //agi + "movl (%%ecx), %%eax \n\t" // ax = ctable[pixel.red] + "movw %%ax, %16 \n\t" // save rr + + "mulb %5 \n\t" // ax = rr*dr + "subw %%ax, %%dx \n\t" // rer = dx = dx - rr*dr + + "movswl %%dx, %%eax \n\t" // save rer + + // distribute error + "leal (, %%eax, 8), %%ecx \n\t" + "subw %%dx, %%cx \n\t" // cx = rer * 7 + "sarw $4, %%cx \n\t" // cx = rer * 7 / 16 + "addb %%cl, 4(%%ebx) \n\t" // err[x+1] += rer * 7 / 16 + + "movl %19, %%ecx \n\t" // ecx = nerr + + "leaw (%%eax, %%eax, 4), %%dx \n\t" // dx = rer * 5 + "sarw $4, %%dx \n\t" // dx = rer * 5 / 16 + "addb %%dl, (%%ecx) \n\t" // nerr[x] += rer * 5 / 16 + + "leaw (%%eax, %%eax, 2), %%dx \n\t" // dx = rer * 3 + "sarw $4, %%dx \n\t" // dx = rer * 3 / 16 + "addb %%dl, -4(%%ecx) \n\t" // nerr[x-1] += rer * 3 / 16 + + "sarw $4, %%ax \n\t" // ax = rer / 16 + "movb %%al, 4(%%ecx) \n\t" // nerr[x+1] = rer / 16 + + + // GREEN + + // depends on ebx, esi, edi + "movzbw 1(%%esi), %%dx \n\t" // dx = image->data[1] + "movsbw 1(%%ebx), %%ax \n\t" // ax = error[1] + "addw %%ax, %%dx \n\t" // pixel.grn = data[1] + error[1] + + "testb %%dh, %%dh \n\t" // test if pixel.grn < 0 or > 255 + "jz .OKGb \n\t" // 0 <= pixel.grn <= 255 + "js .NEGGb \n\t" // pixel.grn < 0 + "movw $0xff, %%dx \n\t" // pixel.grn > 255 + "jmp .OKGb \n" +".NEGGb: \n\t" + "xorw %%dx, %%dx \n" +".OKGb: \n\t" + // partial reg + "leal (%%edi, %%edx, 2), %%ecx \n\t" // ecx = &ctable[pixel.grn] + //agi + "movw (%%ecx), %%ax \n\t" // ax = ctable[pixel.grn] + "movw %%ax, %17 \n\t" // save gg + + "mulb %6 \n\t" // ax = gg*dg + "subw %%ax, %%dx \n\t" // ger = dx = dx - gg*dg + + "movswl %%dx, %%eax \n\t" // save ger + + // distribute error + + "leal (, %%eax, 8), %%ecx \n\t" + "subw %%dx, %%cx \n\t" // cx = ger * 7 + "sarw $4, %%cx \n\t" // cx = ger * 7 / 16 + "addb %%cl, 5(%%ebx) \n\t" // err[x+1] += ger * 7 / 16 + + "movl %19, %%ecx \n\t" // ecx = nerr + + "leaw (%%eax, %%eax, 4), %%dx \n\t" // dx = ger * 5 + "sarw $4, %%dx \n\t" // dx = ger * 5 / 16 + "addb %%dl, 1(%%ecx) \n\t" // nerr[x] += ger * 5 / 16 + + "leaw (%%eax, %%eax, 2), %%dx \n\t" // dx = ger * 3 + "sarw $4, %%dx \n\t" // dx = ger * 3 / 16 + "addb %%dl, -3(%%ecx) \n\t" // nerr[x-1] += ger * 3 / 16 + + "sarw $4, %%ax \n\t" // ax = ger / 16 + "movb %%al, 5(%%ecx) \n\t" // nerr[x+1] = ger / 16 + + + // BLUE + + // depends on ebx, esi + "movzbw 2(%%esi), %%dx \n\t" // dx = image->data[2] + "movsbw 2(%%ebx), %%ax \n\t" // ax = error[2] + "addw %%ax, %%dx \n\t" // pixel.grn = data[2] + error[2] + + "testb %%dh, %%dh \n\t" // test if pixel.blu < 0 or > 255 + "jz .OKBb \n\t" // 0 <= pixel.blu <= 255 + "js .NEGBb \n\t" // pixel.blu < 0 + "movw $0xff, %%dx \n\t" // pixel.blu > 255 + "jmp .OKBb \n" +".NEGBb: \n\t" + "xorw %%dx, %%dx \n" +".OKBb: \n\t" + //partial reg + "leal (%%edi, %%edx, 2), %%ecx \n\t" // ecx = &ctable[pixel.blu] + //agi + "movw (%%ecx), %%ax \n\t" // ax = ctable[pixel.blu] + "movw %%ax, %18 \n\t" // save bb + + "mulb %7 \n\t" // ax = bb*db + "subw %%ax, %%dx \n\t" // ber = dx = dx - bb*db + "movswl %%dx, %%eax \n\t" // save ber + + // distribute error + "leal (, %%eax, 8), %%ecx \n\t" + "subw %%dx, %%cx \n\t" // cx = ber * 7 + "sarw $4, %%cx \n\t" // cx = ber * 7 / 16 + "addb %%cl, 6(%%ebx) \n\t" // err[x+1] += ber * 7 / 16 + + "movl %19, %%ecx \n\t" // ecx = nerr + + "leaw (%%eax, %%eax, 4), %%dx \n\t" // dx = ber * 5 + "sarw $4, %%dx \n\t" // dx = ber * 5 / 16 + "addb %%dl, 2(%%ecx) \n\t" // nerr[x] += ber * 5 / 16 + + "leaw (%%eax, %%eax, 2), %%dx \n\t" // dx = ber * 3 + "sarw $4, %%dx \n\t" // dx = ber * 3 / 16 + "addb %%dl, -4(%%ecx) \n\t" // nerr[x-1] += ber * 3 / 16 + + "sarw $4, %%ax \n\t" // ax = ber / 16 + "movb %%al, 6(%%ecx) \n\t" // nerr[x+1] = ber / 16 + + "andl $0xffff, %%eax \n\t" + // depends on eax & 0xffff0000 == 0 + // calculate the index of the value of the pixel + "movw %16, %%ax \n\t" // ax = rr + "mulb %15 \n\t" // ax = cpcpc*rr + "movw %%ax, %%cx \n\t" + "movw %17, %%ax \n\t" // ax = gg + "mulb %9 \n\t" // ax = cpc*gg + "addw %%cx, %%ax \n\t" // ax = cpc*gg + cpcpc*rr + "addw %18, %%ax \n\t" // ax = cpcpc*rr + cpc*gg + bb + + "movl %8, %%ecx \n\t" + //agi + "leal (%%ecx, %%eax, 4), %%edx \n\t" + //agi + "movb (%%edx), %%cl \n\t" // cl = pixels[ax] + + // store the pixel + "movl %1, %%eax \n\t" + "movb %%cl, (%%eax) \n\t" // *ximage = cl + "incl %1 \n\t" // ximage++ + + // prepare for next iteration on X + + "addl $4, %19 \n\t" // nerr += 4 + "addl $4, %%ebx \n\t" // err += 4 + + "addl %12, %%esi \n\t" // image->data += bpp + + "decl %14 \n\t" // x-- + "jnz .LoopXb \n\t" // if x>0, goto .LoopX + + + "movl %13, %%eax \n\t" + "addl %%eax, %1 \n\t" // add extra offset to ximage + + "jmp .LoopYb \n" + +".Endb: \n\t" + "emms \n\t" + "popal \n\t" + : + : + "m" (image), // %0 + "m" (ximage), // %1 + "m" (err), // %2 + "m" (nerr), // %3 + "m" (ctable), // %4 + "m" (dr), // %5 + "m" (dg), // %6 + "m" (db), // %7 + "m" (pixels), // %8 + "m" (cpc), // %9 + "m" (width), // %10 + "m" (height), // %11 + "m" (bytesPerPixel), // %12 + "m" (line_offset), // %13 + "m" (x), // %14 + "m" (cpcpc), // %15 + "m" (rr), // %16 + "m" (gg), // %17 + "m" (bb), // %18 + "m" (tmp_err), // %19 + "m" (tmp_nerr), // %20 + "m" (ndr), // %21 + "m" (ndg), // %22 + "m" (ndb) // %23 + ); +} + +#endif /* ASM_X86 */ + -- 2.11.4.GIT