чување 1f6afd0fbad25d3b8be5876e34eb01159fcc11b2
родитељ cb9efda7ef130c71f8e6b8c83a54ffa85ff6467f
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Mon, 11 Dec 2023 20:27:50 +0100
Dialogs open in screen center; resizeable main window
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 12, додавања: 185(+), брисања: 128(-)
diff --git a/.gitignore b/.gitignore
@@ -5,3 +5,4 @@
*.swp
WMNewApp
config.h
+cscope.out
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@ CC = cc
CFLAGS = -g -Wall
INSTALL = install
LIBS = -lWMaker -lWINGs -lWUtil -lwraster -lX11
-OBJS = infopanel.o main.o menu.o
+OBJS = infopanel.o main.o menu.o windowmanager.o
PREFIX = /usr/local
PROG = WMNewApp
diff --git a/TODO b/TODO
@@ -3,5 +3,5 @@ TODO
[ ] Info panel
[ ] Manpage
-[ ] Resizeable windows
-[ ] Dialogs open in screen center?
+[x] Resizeable windows
+[x] Dialogs open in screen center?
diff --git a/app.h b/app.h
@@ -8,6 +8,7 @@ struct State {
};
struct WMNewApp {
+ struct State state;
WMAppContext* app;
Pixmap app_icon;
RImage* app_image;
@@ -25,12 +26,13 @@ struct WMNewApp {
XContext xctx;
};
-extern struct State state;
extern struct WMNewApp wma;
void cleanup();
-void create_icon();
-void debug_print_state(struct State* state);
+void create_icon(struct WMNewApp* wma);
+void create_leader_window(struct WMNewApp* wma);
+void create_main_window(struct WMNewApp* wma);
+void debug_print_state(struct WMNewApp* wma);
int error(const int code, const char* msg, ...);
void exit_action(WMWidget* self, void* data);
void handle_keypress(XEvent* event, void* data);
@@ -39,7 +41,6 @@ void init_state(struct State* state);
void not_implemented(WMWidget* self, void* data);
void open_action(WMWidget* self, void* data);
void save_action(WMWidget* self, void* data);
-void set_mainwin_title(struct State* state, char* buf, const size_t size);
+void set_mainwin_title(struct WMNewApp* wma);
void usage(const char* arg0);
-void WMLog(const char* msg, ...);
-
+void WMLog(const struct WMNewApp* wma, const char* msg, ...);
diff --git a/infopanel.c b/infopanel.c
@@ -2,22 +2,22 @@
#include "infopanel.h"
void
-create_info_panel(struct WMInfoPanel* ip)
+create_info_panel(struct WMNewApp* wma, struct WMInfoPanel* ip)
{
WMSize icon_size;
- ip->window = WMCreateWindow(wma.scr, "info");
+ ip->window = WMCreateWindow(wma->scr, "info");
WMResizeWidget(ip->window, 400, 300);
WMSetWindowTitle(ip->window, "Info");
WMSetWindowCloseAction(ip->window, hide_info_panel, NULL);
- icon_size = WMGetPixmapSize(wma.wmpixmap);
+ icon_size = WMGetPixmapSize(wma->wmpixmap);
ip->icon_label = WMCreateLabel(ip->window);
WMResizeWidget(ip->icon_label, icon_size.width, icon_size.height);
WMMoveWidget(ip->icon_label,
80 - icon_size.width,
80 - icon_size.height);
- WMSetLabelImage(ip->icon_label, wma.wmpixmap);
+ WMSetLabelImage(ip->icon_label, wma->wmpixmap);
WMSetLabelImagePosition(ip->icon_label, WIPImageOnly);
WMRealizeWidget(ip->window);
WMMapSubwidgets(ip->window);
diff --git a/infopanel.h b/infopanel.h
@@ -3,6 +3,6 @@ struct WMInfoPanel {
WMWidget* icon_label;
};
-void create_info_panel(struct WMInfoPanel* ip);
+void create_info_panel(struct WMNewApp* wma, struct WMInfoPanel* ip);
void hide_info_panel();
void show_info_panel();
diff --git a/main.c b/main.c
@@ -7,32 +7,18 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
#include "app.h"
#include "infopanel.h"
#include "menu.h"
+#include "windowmanager.h"
+
#include "config.h"
#include "appicon.xpm"
-struct State state;
-struct WMNewApp wma;
-
-void
-cleanup()
-{
- XFree(wma.wmpixmap);
- XFree(wma.scr);
- XFree(wma.rctx);
- XFree(wma.mainwin);
- XFree(wma.main_menu);
- XFree(wma.hints);
- XFree(wma.dpy);
- XFree(wma.class_hint);
- XFree(wma.app_image);
- XFree(wma.app);
-}
-
+/* Assumes leader window has been created */
void
-create_icon()
+create_icon(struct WMNewApp* wma)
{
RContextAttributes attr;
@@ -41,32 +27,84 @@ create_icon()
attr.render_mode = 0;
attr.colors_per_channel = 4;
- if (!(wma.rctx = RCreateContext(wma.dpy, DefaultScreen(wma.dpy), &attr)))
+ if (!(wma->rctx
+ = RCreateContext(wma->dpy, DefaultScreen(wma->dpy), &attr)))
exit(error(1, "RCreateContext failed\n"));
- if (!(wma.app_image = RGetImageFromXPMData(wma.rctx, appicon_xpm)))
+ if (!(wma->app_image = RGetImageFromXPMData(wma->rctx, appicon_xpm)))
exit(error(1, "RGetImageFromXPMData failed\n"));
- if (!RConvertImageMask(wma.rctx, wma.app_image, &wma.app_icon,
- &wma.app_mask, 0))
+ if (!RConvertImageMask(wma->rctx, wma->app_image, &wma->app_icon,
+ &wma->app_mask, 0))
exit(error(1, "RConvertImageMask failed\n"));
- wma.hints->icon_pixmap = wma.app_icon;
- wma.hints->icon_mask = wma.app_mask;
- wma.hints->flags |= (IconPixmapHint | IconMaskHint);
- XSetWMHints(wma.dpy, wma.leader, wma.hints);
+ wma->hints->icon_pixmap = wma->app_icon;
+ wma->hints->icon_mask = wma->app_mask;
+ wma->hints->flags |= (IconPixmapHint | IconMaskHint);
+ XSetWMHints(wma->dpy, wma->leader, wma->hints);
- if (!(wma.wmpixmap
- = WMCreatePixmapFromRImage(wma.scr, wma.app_image, 0)))
+ if (!(wma->wmpixmap
+ = WMCreatePixmapFromRImage(wma->scr, wma->app_image, 0)))
exit(error(1, "WMCreatePixmapFromRImage failed"));
- WMSetApplicationIconPixmap(wma.scr, wma.wmpixmap);
+ WMSetApplicationIconPixmap(wma->scr, wma->wmpixmap);
+}
+
+void
+create_leader_window(struct WMNewApp* wma)
+{
+ wma->leader = XCreateSimpleWindow(wma->dpy, DefaultRootWindow(wma->dpy),
+ 10, 10, 10, 10, 0, 0, 0);
+
+ if (!(wma->class_hint = XAllocClassHint()))
+ exit(error(1, "XAllocClassHint(leader) failed"));
+ wma->class_hint->res_name = "wmnewapp";
+ wma->class_hint->res_class = "WMNewApp";
+ XSetClassHint(wma->dpy, wma->leader, wma->class_hint);
+
+ if (!(wma->hints = XAllocWMHints()))
+ exit(error(1, "XAllocWMHints failed"));
+ wma->hints->window_group = wma->leader;
+ wma->hints->flags = WindowGroupHint;
+ XSetWMHints(wma->dpy, wma->leader, wma->hints);
+}
+
+/* Assumes create_leader_window has previously been called */
+void
+create_main_window(struct WMNewApp* wma)
+{
+ MyGNUstepWMAttributes attributes;
+
+ wma->mainwin = WMCreateWindow(wma->scr, "mainwin");
+ WMLog(wma, "before WMRealizeWidget\n");
+ WMRealizeWidget(wma->mainwin);
+ WMLog(wma, "after WMRealizeWidget\n");
+ set_mainwin_title(wma);
+ WMSetWindowMinSize(wma->mainwin, 200, 200);
+ WMSetWindowCloseAction(wma->mainwin, exit_action, wma);
+
+ XSetClassHint(wma->dpy, WMWidgetXID(wma->mainwin), wma->class_hint);
+ XSetWMHints(wma->dpy, WMWidgetXID(wma->mainwin), wma->hints);
+
+ memset((void*)&attributes, 0, sizeof(MyGNUstepWMAttributes));
+ attributes.window_style = (WMTitledWindowMask
+ | WMMiniaturizableWindowMask | WMResizableWindowMask);
+ attributes.window_level = WMNormalWindowLevel;
+ attributes.extra_flags = GSFullKeyboardEventsFlag;
+ attributes.flags
+ = (GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr);
+ MyWMSetWindowAttributes(wma->dpy, WMWidgetXID(wma->mainwin),
+ &attributes);
+
+ WMMapSubwidgets(wma->mainwin);
+ WMLog(wma, "WMRealizeWidget\n");
+ WMMapWidget(wma->mainwin);
}
void
-debug_print_state(struct State* state)
+debug_print_state(struct WMNewApp* wma)
{
- WMLog("State dump:\n");
- WMLog("===================================\n");
- WMLog("dirty:\t\t%s\n", state->dirty ? "YES" : "NO");
- WMLog("filename:\t[%s]\n", state->filename);
+ WMLog(wma, "State dump:\n");
+ WMLog(wma, "===================================\n");
+ WMLog(wma, "dirty:\t\t%s\n", wma->state.dirty ? "YES" : "NO");
+ WMLog(wma, "filename:\t[%s]\n", wma->state.filename);
}
int
@@ -84,19 +122,21 @@ error(const int code, const char* msg, ...)
void
exit_action(WMWidget* self, void* data)
{
- WMLog("exit_action called\n");
- if (!state.dirty)
+ struct WMNewApp* wma = (struct WMNewApp*)data;
+ WMLog(wma, "exit_action called\n");
+ if (!wma->state.dirty)
exit(0);
- if (WMRunAlertPanel(wma.scr, wma.mainwin, "Confirm",
- "Document %s is modified. Save changes?",
- "Yes", "No", NULL) == 0)
+ if (WMRunAlertPanel(wma->scr, NULL, "Confirm",
+ "Document %s is modified. Save changes?", "Yes", "No", NULL)
+ == 0)
exit(0);
}
void
handle_keypress(XEvent* event, void* data)
{
+ struct WMNewApp* wma = (struct WMNewApp*)data;
int count;
char buffer[64];
KeySym ksym;
@@ -104,39 +144,39 @@ handle_keypress(XEvent* event, void* data)
int meta_pressed = 0;
int shift_pressed = 0;
- WMLog("handle_keypress called\n");
+ WMLog(wma, "handle_keypress called\n");
count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
buffer[count] = 0;
- WMLog("\tbuffer: %s\n", buffer);
- WMLog("\tksym: 0x%lX\n", ksym);
- WMLog("\tstate: %d\n", event->xkey.state);
+ WMLog(wma, "\tbuffer: %s\n", buffer);
+ WMLog(wma, "\tksym: 0x%lX\n", ksym);
+ WMLog(wma, "\tstate: %d\n", event->xkey.state);
ctrl_pressed = event->xkey.state & ControlMask;
meta_pressed = event->xkey.state & Mod1Mask;
shift_pressed = event->xkey.state & ShiftMask;
- WMLog("\tctrl_pressed: %s\n", ctrl_pressed ? "YES" : "NO");
- WMLog("\tmeta_pressed: %s\n", meta_pressed ? "YES" : "NO");
- WMLog("\tshift_pressed: %s\n", shift_pressed ? "YES" : "NO");
+ WMLog(wma, "\tctrl_pressed: %s\n", ctrl_pressed ? "YES" : "NO");
+ WMLog(wma, "\tmeta_pressed: %s\n", meta_pressed ? "YES" : "NO");
+ WMLog(wma, "\tshift_pressed: %s\n", shift_pressed ? "YES" : "NO");
switch (ksym)
{
case XK_F1:
- info_panel_action(wma.mainwin, wma.app);
+ info_panel_action(wma->mainwin, wma);
break;
case XK_o:
if (ctrl_pressed && !meta_pressed && !shift_pressed)
- open_action(wma.mainwin, NULL);
+ open_action(wma->mainwin, wma);
break;
case XK_s:
if (ctrl_pressed && !meta_pressed && !shift_pressed)
- save_action(wma.mainwin, NULL);
+ save_action(wma->mainwin, wma);
break;
case XK_q:
if (ctrl_pressed && !meta_pressed && !shift_pressed)
- exit_action(wma.mainwin, NULL);
+ exit_action(wma->mainwin, wma);
break;
}
}
@@ -144,9 +184,10 @@ handle_keypress(XEvent* event, void* data)
void
info_panel_action(WMWidget* self, void* data)
{
- WMLog("info_panel_action called\n");
+ struct WMNewApp* wma = (struct WMNewApp*)data;
+ WMLog(wma, "info_panel_action called\n");
show_info_panel();
- not_implemented(self, data);
+ not_implemented(self, wma);
}
void
@@ -159,31 +200,34 @@ init_state(struct State* state)
void
not_implemented(WMWidget* self, void* data)
{
- WMRunAlertPanel(wma.scr, wma.mainwin, "Sorry",
+ struct WMNewApp* wma = (struct WMNewApp*)data;
+ WMRunAlertPanel(wma->scr, NULL, "Sorry",
"Function is not yet implemented", "Ok", NULL, NULL);
}
void
open_action(WMWidget* self, void* data)
{
- WMLog("open_action called\n");
+ struct WMNewApp* wma = (struct WMNewApp*)data;
+ WMLog(wma, "open_action called\n");
not_implemented(self, data);
}
void
save_action(WMWidget* self, void* data)
{
- WMLog("save_action called\n");
+ struct WMNewApp* wma = (struct WMNewApp*)data;
+ WMLog(wma, "save_action called\n");
not_implemented(self, data);
}
void
-set_mainwin_title(struct State* state, char* buf, const size_t size)
+set_mainwin_title(struct WMNewApp* wma)
{
- snprintf(buf, size, mainwin_title_fmt, program_name,
- state->dirty ? "*" : "",
- *state->filename ? state->filename : default_filename);
- WMSetWindowTitle(wma.mainwin, wma.mainwin_title);
+ snprintf(wma->mainwin_title, 4095, mainwin_title_fmt, program_name,
+ wma->state.dirty ? "*" : "",
+ *(wma->state.filename) ? wma->state.filename : default_filename);
+ WMSetWindowTitle(wma->mainwin, wma->mainwin_title);
}
void
@@ -195,11 +239,11 @@ usage(const char* arg0)
}
void
-WMLog(const char* msg, ...)
+WMLog(const struct WMNewApp* wma, const char* msg, ...)
{
va_list arg;
- if (!state.debug)
+ if (!wma->state.debug)
return;
va_start(arg, msg);
@@ -210,12 +254,13 @@ WMLog(const char* msg, ...)
int
main(int argc, char** argv)
{
+ struct WMNewApp wma;
int dbg = 0;
int opt;
while ((opt = getopt(argc, argv, "dh")) != -1)
{
- switch(opt)
+ switch (opt)
{
case 'd':
dbg = 1;
@@ -229,58 +274,31 @@ main(int argc, char** argv)
}
}
- init_state(&state);
- state.debug = dbg;
-
- atexit(&cleanup);
+ init_state(&wma.state);
+ wma.state.debug = dbg;
WMInitializeApplication("WMNewApp", &argc, argv);
if (!(wma.dpy = XOpenDisplay("")))
- return error(1, "XOpenDisplay failed");
+ exit(error(1, "XOpenDisplay failed"));
- wma.leader = XCreateSimpleWindow(wma.dpy, DefaultRootWindow(wma.dpy),
- 10, 10, 10, 10, 0, 0, 0);
-
- if (!(wma.class_hint = XAllocClassHint()))
- exit(error(1, "XAllocClassHint(leader) failed"));
- wma.class_hint->res_name = "wmnewapp";
- wma.class_hint->res_class = "WMNewApp";
- XSetClassHint(wma.dpy, wma.leader, wma.class_hint);
-
- if (!(wma.hints = XAllocWMHints()))
- exit(error(1, "XAllocWMHints failed"));
- wma.hints->window_group = wma.leader;
- wma.hints->flags = WindowGroupHint;
- XSetWMHints(wma.dpy, wma.leader, wma.hints);
+ create_leader_window(&wma);
XSetCommand(wma.dpy, wma.leader, argv, argc);
wma.xctx = XUniqueContext();
+ wma.scr = WMCreateScreen(wma.dpy, DefaultScreen(wma.dpy));
+ wma.app = WMAppCreateWithMain(wma.dpy, DefaultScreen(wma.dpy),
+ wma.leader);
- WMInitializeApplication("WMPoe", &argc, argv);
- wma.scr = WMCreateScreen(wma.dpy, DefaultScreen(wma.dpy));
- wma.app = WMAppCreateWithMain(wma.dpy, DefaultScreen(wma.dpy),
- wma.leader);
-
- wma.mainwin = WMCreateWindow(wma.scr, "mainwin");
- WMRealizeWidget(wma.mainwin);
-
- XSetClassHint(wma.dpy, WMWidgetXID(wma.mainwin), wma.class_hint);
- XSetWMHints(wma.dpy, WMWidgetXID(wma.mainwin), wma.hints);
-
- create_icon();
- //create_info_panel();
- create_main_menu(wma.app);
+ create_main_window(&wma);
+ create_icon(&wma);
+ create_main_menu(&wma);
+ // create_info_panel();
- set_mainwin_title(&state, wma.mainwin_title, 4095);
- WMSetWindowMinSize(wma.mainwin, 200, 200);
- WMSetWindowCloseAction(wma.mainwin, exit_action, NULL);
- WMMapSubwidgets(wma.mainwin);
- WMMapWidget(wma.mainwin);
WMSetFocusToWidget(wma.mainwin);
XSaveContext(wma.dpy, WMWidgetXID(wma.mainwin), wma.xctx, NULL);
WMCreateEventHandler(WMWidgetView(wma.mainwin), KeyPressMask,
- handle_keypress, NULL);
+ handle_keypress, &wma);
XFlush(wma.dpy);
diff --git a/make-new-app.sh b/make-new-app.sh
@@ -77,6 +77,8 @@ sed 's/WMNewApp/'$app_name'/g;s/wmnewapp/'$res_name'/g' main.c \
> "$full_app_dir"/main.c
cp menu.c "$full_app_dir"/menu.c
cp menu.h "$full_app_dir"/menu.h
+cp windowmanager.c "$full_app_dir"/windowmanager.c
+cp windowmanager.h "$full_app_dir"/windowmanager.h
cp LICENSE "$full_app_dir"/LICENSE
cat <<ENDREADME > "$full_app_dir"/README
$app_name
diff --git a/menu.c b/menu.c
@@ -2,24 +2,24 @@
#include "config.h"
void
-create_main_menu(WMAppContext* app)
+create_main_menu(struct WMNewApp* wma)
{
WMMenu* submenu;
- wma.main_menu = WMMenuCreate(wma.app, (char*)program_name);
+ wma->main_menu = WMMenuCreate(wma->app, (char*)program_name);
- submenu = WMMenuCreate(wma.app, "Info");
- WMMenuAddSubmenu(wma.main_menu, "Info", submenu);
+ submenu = WMMenuCreate(wma->app, "Info");
+ WMMenuAddSubmenu(wma->main_menu, "Info", submenu);
WMMenuAddItem(submenu, "Info Panel...", (WMMenuAction)info_panel_action,
- app, NULL, "f1");
+ wma->app, NULL, "f1");
- WMMenuAddItem(wma.main_menu, "Open...", (WMMenuAction)open_action, NULL,
+ WMMenuAddItem(wma->main_menu, "Open...", (WMMenuAction)open_action, NULL,
NULL, "^o");
- WMMenuAddItem(wma.main_menu, "Save...", (WMMenuAction)save_action, NULL,
+ WMMenuAddItem(wma->main_menu, "Save...", (WMMenuAction)save_action, NULL,
NULL, "^s");
- WMMenuAddItem(wma.main_menu, "Quit", (WMMenuAction)exit_action, NULL,
+ WMMenuAddItem(wma->main_menu, "Quit", (WMMenuAction)exit_action, NULL,
NULL, "^q");
- WMAppSetMainMenu(wma.app, wma.main_menu);
- WMRealizeMenus(wma.app);
+ WMAppSetMainMenu(wma->app, wma->main_menu);
+ WMRealizeMenus(wma->app);
}
diff --git a/menu.h b/menu.h
@@ -1 +1 @@
-void create_main_menu(WMAppContext* app);
+void create_main_menu(struct WMNewApp* app);
diff --git a/windowmanager.c b/windowmanager.c
@@ -0,0 +1,11 @@
+#include "windowmanager.h"
+
+void MyWMSetWindowAttributes(Display* dpy, Window window, MyGNUstepWMAttributes* attributes)
+{
+ Atom atom;
+
+ atom = XInternAtom(dpy, "_GNUSTEP_WM_ATTR", False);
+ XChangeProperty(dpy, window, atom, atom, 32, PropModeReplace,
+ (unsigned char*)attributes,
+ sizeof(MyGNUstepWMAttributes) / sizeof(unsigned long));
+}
+\ No newline at end of file
diff --git a/windowmanager.h b/windowmanager.h
@@ -0,0 +1,22 @@
+#ifndef _WINDOWMANAGER_H_
+#define _WINDOWMANAGER_H_
+
+#include <X11/Xlib.h>
+
+typedef struct
+{
+ unsigned long flags;
+ unsigned long window_style;
+ unsigned long window_level;
+ unsigned long reserved;
+ Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
+ Pixmap close_pixmap; /* pixmap for close button */
+ Pixmap miniaturize_mask; /* miniaturize pixmap mask */
+ Pixmap close_mask; /* close pixmap mask */
+ unsigned long extra_flags;
+} MyGNUstepWMAttributes;
+
+void MyWMSetWindowAttributes(Display* dpy, Window window,
+ MyGNUstepWMAttributes* attributes);
+
+#endif
+\ No newline at end of file